我有一个包含 >101K 行的 pandas 数据框,我试图根据日期计算
won
列的平均值。逻辑是,对于每一行,找到 won
row['created_on']
的所有行的 < current row['created_on']
的平均值。请注意,我并不是试图获得 won
列的累积平均值 ,因为这个问题被识别为重复的。建议的重复项提供了一种按行计算累积值的方法,但我希望尝试按 date 计算累积值,即 rolling_won_prop
的所有值对于给定日期应该相同,但不应该是按行累积。
我可以用
计算一个简单的值def get_win_prop(df, d) -> float:
mask = (df['created_on'] < d)
prop = df[mask].won.mean()
return(prop)
get_win_prop(d, '2022-10-25')
当我尝试将此函数与
pd.assign()
一起使用时,我没有收到任何错误,但所有值最终都是 NaN
:
d.assign(rolling_won_prop = lambda x: get_win_prop(x, x.created_on))
我错过了什么?我会假设
get_win_prop()
fx 就是我所需要的。在 pandas 中是否有更有效的方法来做到这一点?请注意,我在下面提供了数据示例,但在计算 get_win_prop()
值之前,我需要按客户 ID 列进行分组。
我提出了一个适用于下面这个玩具数据集的示例解决方案,但可能无法很好地扩展:
result = []
for i in d.created_on.unique():
prev_vals = d[d['created_on'] < i]
result.append(prev_vals.won.mean())
d.merge(pd.DataFrame({'created_on': d.created_on.unique(),
'rolling_won_prop ': result}), how = 'left')
我用一个
for
循环拼凑了一个不优雅的解决方案,但产生了适当的结果:
results = []
for i in d.created_on.unique():
prev_vals = d[d['created_on'] < i]
results.append(prev_vals.won.mean())
d.merge(pd.DataFrame({'created_on': d.created_on.unique(),
'rolling_won_prop ': results}), how = 'left')
鉴于我有一个额外的客户 ID 列(此处提供的 MWE 中不存在),我可以将上述解决方案调整为按客户 ID 进行分组,但这仍然不是一个主意。如果可能的话,我宁愿在 pandas 框架中使用这个解决方案。
样本数据
import pandas as pd
from pandas import Timestamp
d = pd.DataFrame({'created_on': [Timestamp('2022-09-22 00:00:00'), Timestamp('2022-10-14 00:00:00'),Timestamp('2022-10-19 00:00:00'),Timestamp('2022-10-25 00:00:00'),Timestamp('2022-11-02 00:00:00'),
Timestamp('2022-11-04 00:00:00'),Timestamp('2022-11-16 00:00:00'),Timestamp('2022-11-28 00:00:00'),Timestamp('2022-11-28 00:00:00'),Timestamp('2022-12-07 00:00:00'),
Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00'),Timestamp('2022-12-21 00:00:00')],
'n_lines': [7, 3, 7, 6, 6, 4, 5, 3, 10, 3, 6, 6, 9, 6],
'n_pieces': [606, 202, 706, 765, 255, 803, 1004, 2702, 1909, 546, 555, 555, 558,555],
'quote_total': [1780.4299999999998, 3575.4600000000005, 11762.079999999994, 6725.160000000002, 995.9300000000001, 1644.2100000000003, 2620.2299999999996,
8082.090000000001, 5302.320000000001, 1959.7599999999998, 8734.67, 9792.3, 0.0, 9720.71],
'won': [1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0]})
假设日期按“id”排序,您仍然可以从链接的帖子中受益。您只需随后用第一个值填充
['id', 'group']
的重复组合即可。含义:
最小可重现示例,包含
'id'
组
import pandas as pd
import numpy as np
data = {'id': np.repeat(['A', 'B'], [6,6]),
'created_on': np.tile(np.repeat(pd.date_range('2024-01-01', periods=4),
[1,2,1,2]), 2),
'won': np.tile([1, 0], 6)}
df = pd.DataFrame(data)
df
id created_on won
0 A 2024-01-01 1
1 A 2024-01-02 0
2 A 2024-01-02 1
3 A 2024-01-03 0
4 A 2024-01-04 1
5 A 2024-01-04 0
6 B 2024-01-01 1
7 B 2024-01-02 0
8 B 2024-01-02 1
9 B 2024-01-03 0
10 B 2024-01-04 1
11 B 2024-01-04 0
代码
gp = df.groupby('id')['won']
df['rolling_won_prop'] = (gp.cumsum() - df['won'])/gp.cumcount()
df['rolling_won_prop'] = (df.groupby(['id', 'created_on'])
['rolling_won_prop'].transform('first')
)
输出:
id created_on won rolling_won_prop
0 A 2024-01-01 1 NaN
1 A 2024-01-02 0 1.000000
2 A 2024-01-02 1 1.000000
3 A 2024-01-03 0 0.666667 # e.g. (1 + 0 + 1) / 3
4 A 2024-01-04 1 0.500000 # e.g. (1 + 0 + 1 + 0) / 4
5 A 2024-01-04 0 0.500000 # filled from prev row
6 B 2024-01-01 1 NaN
7 B 2024-01-02 0 1.000000
8 B 2024-01-02 1 1.000000
9 B 2024-01-03 0 0.666667
10 B 2024-01-04 1 0.500000
11 B 2024-01-04 0 0.500000