Совокупная сумма применяется только к 1 столбцу python

Я хотел бы применить cumsum только к 1 конкретному столбцу, поскольку у меня есть другие значения в разных столбцах, которые должны оставаться неизменными.

Это сценарий, который у меня есть до сих пор

df.groupby(by=['name','day']).sum().groupby(level=[0]).cumsum()

Однако этот скрипт приводит к тому, что все мои столбцы в моем pandas df будут накапливаться. Единственный столбец, который должен накапливать сумму, это data.

В соответствии с просьбой, вот некоторые примеры данных:

df = pd.DataFrame({'ID': ["880022443344556677787", "880022443344556677782", "880022443344556677787",
                          "880022443344556677782", "880022443344556677787", "880022443344556677782",
                          "880022443344556677781"],
                   'Month': ["201701", "201701", "201702", "201702", "201703", "201703", "201703"],
                   'Usage': [20, 40, 100, 50, 30, 30, 2000],
                   'Sec': [10, 15, 20, 1, 5, 6, 30]})

                      ID   Month  Sec  Usage
0  880022443344556677787  201701   10     20
1  880022443344556677782  201701   15     40
2  880022443344556677787  201702   20    100
3  880022443344556677782  201702    1     50
4  880022443344556677787  201703    5     30
5  880022443344556677782  201703    6     30
6  880022443344556677781  201703   30   2000

Желаемый результат

                      ID   Month  Sec  Usage
0  880022443344556677787  201701   10     20
1  880022443344556677782  201701   15     40
2  880022443344556677787  201702   20    120
3  880022443344556677782  201702    1     90
4  880022443344556677787  201703    5    150
5  880022443344556677782  201703    6    120
6  880022443344556677781  201703   30   2000

person Joe_ft    schedule 01.03.2017    source источник


Ответы (3)


Я думаю, вам нужно set_index для столбцов, где НЕ нужно cumsum - я динамически нахожу их по list comprehension:

cumsum_col = 'Usage'
df1 = df.groupby(by=['ID','Month'], sort=False).sum()
cols = [col for col in df1.columns if col != cumsum_col]

df1 = df1.set_index(cols, append=True).groupby(level=[0]).cumsum().reset_index()
print (df1)
                      ID   Month  Sec  Usage
0  880022443344556677787  201701   10     20
1  880022443344556677782  201701   15     40
2  880022443344556677787  201702   20    120
3  880022443344556677782  201702    1     90
4  880022443344556677787  201703    5    150
5  880022443344556677782  201703    6    120
6  880022443344556677781  201703   30   2000

РЕДАКТИРОВАТЬ:

cumsum_col = 'Usage'
df2 = df.groupby(by=['ID','Month'], sort=False).sum()
cols = [col for col in df2.columns if col != cumsum_col]
df1 = df2.set_index(cols, append=True).groupby(level=[0]).cumsum()
df1 = df2.assign(Usage_cumsum = df1.reset_index(level=2, drop=True)).reset_index()
print (df1)
                      ID   Month  Sec  Usage  Usage_cumsum
0  880022443344556677787  201701   10     20            20
1  880022443344556677782  201701   15     40            40
2  880022443344556677787  201702   20    100           120
3  880022443344556677782  201702    1     50            90
4  880022443344556677787  201703    5     30           150
5  880022443344556677782  201703    6     30           120
6  880022443344556677781  201703   30   2000          2000

РЕДАКТИРОВАТЬ1:

В вашем образце данные не являются агрегированными sum, поэтому данные немного изменены (решение похоже, но не такое же, как другое):

df = pd.DataFrame({'ID': ["880022443344556677787", "880022443344556677782", "880022443344556677787",
                          "880022443344556677782", "880022443344556677787", "880022443344556677782",
                          "880022443344556677781"],
                   'Month': ["201701", "201701", "201701", "201702", "201703", "201701", "201703"],
                   'Usage': [20, 40, 100, 50, 30, 30, 2000],
                   'Sec': [10, 15, 20, 1, 5, 6, 30]})

print (df)
                      ID   Month  Sec  Usage
0  880022443344556677787  201701   10     20
1  880022443344556677782  201701   15     40
2  880022443344556677787  201701   20    100
3  880022443344556677782  201702    1     50
4  880022443344556677787  201703    5     30
5  880022443344556677782  201701    6     30
6  880022443344556677781  201703   30   2000
#aggregate sum to all columns
df1 = df.groupby(['ID', 'Month']).sum() 
print (df1)
                              Sec  Usage
ID                    Month             
880022443344556677781 201703   30   2000
880022443344556677782 201701   21     70
                      201702    1     50
880022443344556677787 201701   30    120
                      201703    5     30

#aggregate cumcum to Usage column only 
s = df1.groupby(level=0)['Usage'].cumsum()
print (s)
ID                     Month 
880022443344556677781  201703    2000
880022443344556677782  201701      70
                       201702     120
880022443344556677787  201701     120
                       201703     150
Name: Usage, dtype: int64
#join cumsum series to aggregate df1
df3 = df1.join(s, rsuffix='_cumsum').reset_index()
print (df3)
                      ID   Month  Sec  Usage  Usage_cumsum
0  880022443344556677781  201703   30   2000          2000
1  880022443344556677782  201701   21     70            70
2  880022443344556677782  201702    1     50           120
3  880022443344556677787  201701   30    120           120
4  880022443344556677787  201703    5     30           150
person jezrael    schedule 01.03.2017
comment
Можно ли добавить дополнительный столбец с данными суммарной суммы вместо его замены? - person Joe_ft; 01.03.2017
comment
Не уверен, что происходит, но когда я применяю его к своему df, ваш первый метод работает, но новый с дополнительным столбцом с общей суммой возвращается со значениями NaN. Вы знаете, что происходит? - person Joe_ft; 01.03.2017
comment
Таким образом, ваши реальные данные имеют больше столбцов, поэтому нужно изменить df1.reset_index(level=[2,3,4], drop=True) - каждый уровень для дополнительного столбца. Но я изменяю другое решение, дайте мне секунду. - person jezrael; 01.03.2017

Рассмотрим кадр данных df

df = pd.DataFrame(dict(
        name=list('aaaaaaaabbbbbbbb'),
        day=np.tile(np.arange(2).repeat(4), 2),
        data=np.arange(16)
    ))

Во-первых, вы выполняете cumsum для определенного столбца, называя столбец после оператора groupby.

Во-вторых, вы можете добавить это обратно в фрейм данных df с помощью join

d2 = df.groupby(['name', 'day']).data.sum().groupby(level=0).cumsum()

df.join(d2, on=['name', 'day'], rsuffix='_cum')

    data  day name  data_cum
0      0    0    a         6
1      1    0    a         6
2      2    0    a         6
3      3    0    a         6
4      4    1    a        28
5      5    1    a        28
6      6    1    a        28
7      7    1    a        28
8      8    0    b        38
9      9    0    b        38
10    10    0    b        38
11    11    0    b        38
12    12    1    b        92
13    13    1    b        92
14    14    1    b        92
15    15    1    b        92
person piRSquared    schedule 01.03.2017

Вы уже можете сделать кумулятивную сумму ('cumsum') как агрегацию для df.groupby. Вам нужно передать его 'cumsum' в виде строки в качестве функции агрегирования в столбец «данные».

df.groupby(['name','day']).agg({'data': 'cumsum'})
person Osama Haggag    schedule 01.03.2017
comment
Это неправильно, потому что сначала нужно агрегировать sum, а затем группировать по первому уровню только для агрегации cumsum. - person jezrael; 01.03.2017