条件 运行 总和 Pandas 仅适用于所有先前的值
Conditional Running Sum in Pandas for All Previous Values Only
假设我有以下 DataFrame:
df = pd.DataFrame({'Event': ['A', 'B', 'A', 'A', 'B', 'C', 'B', 'B', 'A', 'C'],
'Date': ['2019-01-01', '2019-02-01', '2019-03-01', '2019-03-01', '2019-02-15',
'2019-03-15', '2019-04-05', '2019-04-05', '2019-04-15', '2019-06-10'],
'Sale': [100, 200, 150, 200, 150, 100, 300, 250, 500, 400]})
df['Date'] = pd.to_datetime(df['Date'])
df
Event Date Sale
A 2019-01-01 100
B 2019-02-01 200
A 2019-03-01 150
A 2019-03-01 200
B 2019-02-15 150
C 2019-03-15 100
B 2019-04-05 300
B 2019-04-05 250
A 2019-04-15 500
C 2019-06-10 400
我想得到以下结果:
Event Date Sale Total_Previous_Sale
A 2019-01-01 100 0
B 2019-02-01 200 0
A 2019-03-01 150 100
A 2019-03-01 200 100
B 2019-02-15 150 200
C 2019-03-15 100 0
B 2019-04-05 300 350
B 2019-04-05 250 350
A 2019-04-15 500 450
C 2019-06-10 400 100
其中 df['Total_Previous_Sale']
是事件 (df['Event']
) 在其相邻日期 (df['Date']
) 之前发生时的总销售额 (df['Sale']
)。例如,
- 事件A发生在2019-01-01之前的销售总额为0,
- 事件A发生在2019-03-01之前的总销售量为100,
- 事件A在2019-04-15之前的销售总额为100 + 150 + 200 = 450。
基本上,它与条件累积和几乎相同,但仅适用于所有先前值(不包括当前值[s])。我能够使用此行获得所需的结果:
df['Sale_Total'] = [df.loc[(df['Event'] == df.loc[i, 'Event']) & (df['Date'] < df.loc[i, 'Date']),
'Sale'].sum() for i in range(len(df))]
虽然速度很慢,但效果很好。我相信有更好更快的方法来做到这一点。我试过这些行:
df['Total_Previuos_Sale'] = df[df['Date'] < df['Date']].groupby(['Event'])['Sale'].cumsum()
或
df['Total_Previuos_Sale'] = df.groupby(['Event'])['Sale'].shift(1).cumsum().fillna(0)
但它产生了 NaN 或产生了不需要的结果。
首先将 sum
每个 Event
和 Date
聚合 MultiIndex
,然后按第一级 Event
分组并使用 shift
和累积用 lambda 函数和最后一个 join
求和:
s = (df.groupby(['Event', 'Date'])['Sale']
.sum().groupby(level=0)
.apply(lambda x: x.shift(1).cumsum())
.fillna(0)
df = df.join(s.rename('Total_Previuos_Sale'), on=['Event','Date'])
print (df)
Event Date Sale Total_Previuos_Sale
0 A 2019-01-01 100 0.0
1 B 2019-02-01 200 0.0
2 A 2019-03-01 150 100.0
3 A 2019-03-01 200 100.0
4 B 2019-02-15 150 200.0
5 C 2019-03-15 100 0.0
6 B 2019-04-05 300 350.0
7 B 2019-04-05 250 350.0
8 A 2019-04-15 500 450.0
9 C 2019-06-10 400 100.0
终于,我找到了更好更快的方法来获得想要的结果。事实证明,这很容易。可以试试:
df['Total_Previous_Sale'] = df.groupby('Event')['Sale'].cumsum() \
- df.groupby(['Event', 'Date'])['Sale'].cumsum()
假设我有以下 DataFrame:
df = pd.DataFrame({'Event': ['A', 'B', 'A', 'A', 'B', 'C', 'B', 'B', 'A', 'C'],
'Date': ['2019-01-01', '2019-02-01', '2019-03-01', '2019-03-01', '2019-02-15',
'2019-03-15', '2019-04-05', '2019-04-05', '2019-04-15', '2019-06-10'],
'Sale': [100, 200, 150, 200, 150, 100, 300, 250, 500, 400]})
df['Date'] = pd.to_datetime(df['Date'])
df
Event Date Sale
A 2019-01-01 100
B 2019-02-01 200
A 2019-03-01 150
A 2019-03-01 200
B 2019-02-15 150
C 2019-03-15 100
B 2019-04-05 300
B 2019-04-05 250
A 2019-04-15 500
C 2019-06-10 400
我想得到以下结果:
Event Date Sale Total_Previous_Sale
A 2019-01-01 100 0
B 2019-02-01 200 0
A 2019-03-01 150 100
A 2019-03-01 200 100
B 2019-02-15 150 200
C 2019-03-15 100 0
B 2019-04-05 300 350
B 2019-04-05 250 350
A 2019-04-15 500 450
C 2019-06-10 400 100
其中 df['Total_Previous_Sale']
是事件 (df['Event']
) 在其相邻日期 (df['Date']
) 之前发生时的总销售额 (df['Sale']
)。例如,
- 事件A发生在2019-01-01之前的销售总额为0,
- 事件A发生在2019-03-01之前的总销售量为100,
- 事件A在2019-04-15之前的销售总额为100 + 150 + 200 = 450。
基本上,它与条件累积和几乎相同,但仅适用于所有先前值(不包括当前值[s])。我能够使用此行获得所需的结果:
df['Sale_Total'] = [df.loc[(df['Event'] == df.loc[i, 'Event']) & (df['Date'] < df.loc[i, 'Date']),
'Sale'].sum() for i in range(len(df))]
虽然速度很慢,但效果很好。我相信有更好更快的方法来做到这一点。我试过这些行:
df['Total_Previuos_Sale'] = df[df['Date'] < df['Date']].groupby(['Event'])['Sale'].cumsum()
或
df['Total_Previuos_Sale'] = df.groupby(['Event'])['Sale'].shift(1).cumsum().fillna(0)
但它产生了 NaN 或产生了不需要的结果。
首先将 sum
每个 Event
和 Date
聚合 MultiIndex
,然后按第一级 Event
分组并使用 shift
和累积用 lambda 函数和最后一个 join
求和:
s = (df.groupby(['Event', 'Date'])['Sale']
.sum().groupby(level=0)
.apply(lambda x: x.shift(1).cumsum())
.fillna(0)
df = df.join(s.rename('Total_Previuos_Sale'), on=['Event','Date'])
print (df)
Event Date Sale Total_Previuos_Sale
0 A 2019-01-01 100 0.0
1 B 2019-02-01 200 0.0
2 A 2019-03-01 150 100.0
3 A 2019-03-01 200 100.0
4 B 2019-02-15 150 200.0
5 C 2019-03-15 100 0.0
6 B 2019-04-05 300 350.0
7 B 2019-04-05 250 350.0
8 A 2019-04-15 500 450.0
9 C 2019-06-10 400 100.0
终于,我找到了更好更快的方法来获得想要的结果。事实证明,这很容易。可以试试:
df['Total_Previous_Sale'] = df.groupby('Event')['Sale'].cumsum() \
- df.groupby(['Event', 'Date'])['Sale'].cumsum()