我有一个在R中使用dplyr很容易解决的问题,但是在Python中似乎找不到一种简单的方法。我有一个df,其中id(=customerid)、s(=store)、m(=month)和ttl(=total )作为列。我想在id+s上计算多个新列--例如,最后3个月的购买和最小购买。
示例(最后两列是新列):
id s m ttl ttl_3 min_id_s
1 A 1/1/2020 7 nan 3
1 A 2/1/2020 3 nan 3
1 A 3/1/2020 7 17 3
1 A 4/1/2020 6 16 3
1 A 5/1/2020 7 20 3
1 A 6/1/2020 7 20 3
1 B 1/1/2020 6 nan 6
1 B 2/1/2020 10 nan 6
1 B 3/1/2020 8 24 6
1 B 4/1/2020 8 26 6
1 B 5/1/2020 10 26 6
1 B 6/1/2020 8 26 6
2 A 1/1/2020 4 nan 1
2 A 2/1/2020 3 15 1
2 A 3/1/2020 10 17 1
2 A 4/1/2020 6 19 1
2 A 5/1/2020 4 20 1
2 A 6/1/2020 1 11 1我试过以下几种方法:
grp = df.groupby(['id','s'])
df = df.assign(ttl_3 = grp['ttl'].apply(lambda x: x.rolling(window=3)).sum(), min_id_s = grp['ttl'].min())我得到以下错误:
无法访问'DataFrameGroupBy‘对象的可调用属性'assign’,请尝试使用'apply‘方法
我知道不需要赋值就可以解决这个问题,但是接下来我必须为每个新列设置一个行,因为我需要很多这些,所以我正在寻找一个解决办法。
我也研究过pyjanitor的add_columns,但是它似乎不适用于groupby。
在R中,下面的代码解决了这个问题,在变体中,我可以继续添加列:
df = df %>% group_by(id, s) %>% mutate(ttl_3 = runner(ttl, k=3, f=sum), min_id_s = min(ttl))发布于 2020-10-11 10:03:52
对于python语法和熊猫,逻辑几乎是相同的。
t = '''
id s m ttl
1 A 1/1/2020 7
1 A 2/1/2020 3
1 A 3/1/2020 7
1 A 4/1/2020 6
1 A 5/1/2020 7
1 A 6/1/2020 7
1 B 1/1/2020 6
1 B 2/1/2020 10
1 B 3/1/2020 8
1 B 4/1/2020 8
1 B 5/1/2020 10
1 B 6/1/2020 8
2 A 1/1/2020 4
2 A 2/1/2020 3
2 A 3/1/2020 10
2 A 4/1/2020 6
2 A 5/1/2020 4
2 A 6/1/2020 1 '''
import pandas as pd
import io
df = pd.read_csv(io.StringIO(t), sep='\s+')尽量接近dplyr。
按id和s分组并计算新列。可以使用rolling方法计算多个agg列。
您可以使用assign,但也必须为每个聚合编写一行。
group = df.groupby(['id','s'])['ttl']
df['ttl_3'] = group.rolling(3).sum().reset_index(level=(0,1), drop=True)
df['min_id_s'] = group.transform('min')
#df = df.assign(
# ttl_3 = group.rolling(3).sum().reset_index(level=(0,1), drop=True),
# min_id_s = group.transform('min'))
df退出:
id s m ttl ttl_3 min_id_s
0 1 A 1/1/2020 7 NaN 3
1 1 A 2/1/2020 3 NaN 3
2 1 A 3/1/2020 7 17.0 3
3 1 A 4/1/2020 6 16.0 3
4 1 A 5/1/2020 7 20.0 3
5 1 A 6/1/2020 7 20.0 3
6 1 B 1/1/2020 6 NaN 6
7 1 B 2/1/2020 10 NaN 6
8 1 B 3/1/2020 8 24.0 6
9 1 B 4/1/2020 8 26.0 6
10 1 B 5/1/2020 10 26.0 6
11 1 B 6/1/2020 8 26.0 6
12 2 A 1/1/2020 4 NaN 1
13 2 A 2/1/2020 3 NaN 1
14 2 A 3/1/2020 10 17.0 1
15 2 A 4/1/2020 6 19.0 1
16 2 A 5/1/2020 4 20.0 1
17 2 A 6/1/2020 1 11.0 1用rolling聚合agg的多列
group = df.groupby(['id','s'])['ttl']
df[['ttl_3_sum','ttl_3_mean']] = group.rolling(3).agg(['sum','mean']).reset_index(level=(0,1), drop=True)退出:
id s m ttl ttl_3_sum ttl_3_mean
0 1 A 1/1/2020 7 NaN NaN
1 1 A 2/1/2020 3 NaN NaN
2 1 A 3/1/2020 7 17.0 5.666667
3 1 A 4/1/2020 6 16.0 5.333333
4 1 A 5/1/2020 7 20.0 6.666667
5 1 A 6/1/2020 7 20.0 6.666667
6 1 B 1/1/2020 6 NaN NaN
7 1 B 2/1/2020 10 NaN NaN
8 1 B 3/1/2020 8 24.0 8.000000
9 1 B 4/1/2020 8 26.0 8.666667
10 1 B 5/1/2020 10 26.0 8.666667
11 1 B 6/1/2020 8 26.0 8.666667
12 2 A 1/1/2020 4 NaN NaN
13 2 A 2/1/2020 3 NaN NaN
14 2 A 3/1/2020 10 17.0 5.666667
15 2 A 4/1/2020 6 19.0 6.333333
16 2 A 5/1/2020 4 20.0 6.666667
17 2 A 6/1/2020 1 11.0 3.666667使用rolling从多个列聚合多个列,并使用agg。列必须是数字的。据我所知,transform不支持多个聚合。
生成滚动聚合的随机数值列
import numpy as np
df['ttl2'] = np.random.rand(len(df))没有从多个列聚合的选定列的groupby。例如,使用自定义函数
group = df.groupby(['id','s'])
df[['ttl_3_sum', 'ttl2_lambda']] = (group.rolling(3)
.agg({'ttl':'sum', 'ttl2': lambda x: x.sum()/x.min()})
.reset_index(level=(0,1), drop=True))
df退出:
id s m ttl ttl2 ttl_3_sum ttl2_lambda
0 1 A 1/1/2020 7 0.032482 NaN NaN
1 1 A 2/1/2020 3 0.998115 NaN NaN
2 1 A 3/1/2020 7 0.689431 17.0 52.953016
3 1 A 4/1/2020 6 0.897444 16.0 3.749456
4 1 A 5/1/2020 7 0.484360 20.0 4.276231
5 1 A 6/1/2020 7 0.971768 20.0 4.859138
6 1 B 1/1/2020 6 0.238363 NaN NaN
7 1 B 2/1/2020 10 0.740311 NaN NaN
8 1 B 3/1/2020 8 0.641598 24.0 6.797507
9 1 B 4/1/2020 8 0.984911 26.0 3.688945
10 1 B 5/1/2020 10 0.043379 26.0 38.495141
11 1 B 6/1/2020 8 0.700253 26.0 39.847293
12 2 A 1/1/2020 4 0.437082 NaN NaN
13 2 A 2/1/2020 3 0.465313 NaN NaN
14 2 A 3/1/2020 10 0.698976 17.0 3.663777
15 2 A 4/1/2020 6 0.430087 19.0 3.707103
16 2 A 5/1/2020 4 0.949536 20.0 4.832976
17 2 A 6/1/2020 1 0.904986 11.0 5.311974https://stackoverflow.com/questions/64302315
复制相似问题