熊猫:GroupBy .pipe() 与 .apply()
Posted
技术标签:
【中文标题】熊猫:GroupBy .pipe() 与 .apply()【英文标题】:pandas: GroupBy .pipe() vs .apply() 【发布时间】:2018-04-23 21:31:24 【问题描述】:在 pandas documentation 的示例中,关于 GroupBy 对象的新 .pipe()
方法,接受相同 lambda 的 .apply()
方法将返回相同的结果。
In [195]: import numpy as np
In [196]: n = 1000
In [197]: df = pd.DataFrame('Store': np.random.choice(['Store_1', 'Store_2'], n),
.....: 'Product': np.random.choice(['Product_1', 'Product_2', 'Product_3'], n),
.....: 'Revenue': (np.random.random(n)*50+10).round(2),
.....: 'Quantity': np.random.randint(1, 10, size=n))
In [199]: (df.groupby(['Store', 'Product'])
.....: .pipe(lambda grp: grp.Revenue.sum()/grp.Quantity.sum())
.....: .unstack().round(2))
Out[199]:
Product Product_1 Product_2 Product_3
Store
Store_1 6.93 6.82 7.15
Store_2 6.69 6.64 6.77
我可以看到 pipe
功能与 apply
的 DataFrame 对象有何不同,但 GroupBy 对象却没有。有没有人解释或举例说明pipe
可以做什么,而apply
不能用于 GroupBy?
【问题讨论】:
【参考方案1】:pipe
所做的是允许您传递可调用对象,并期望调用 pipe
的对象是传递给可调用对象的对象。
对于apply
,我们假设调用apply
的对象具有子组件,每个子组件将传递给传递给apply
的可调用对象。在groupby
的上下文中,子组件是调用groupby
的数据帧的切片,其中每个切片本身就是一个数据帧。这与groupby
系列类似。
您可以在groupby
上下文中使用pipe
所做的主要区别在于,您可以在groupby
对象的整个范围内使用可调用对象。对于申请,你只知道本地切片。
设置
考虑df
df = pd.DataFrame(dict(
A=list('XXXXYYYYYY'),
B=range(10)
))
A B
0 X 0
1 X 1
2 X 2
3 X 3
4 Y 4
5 Y 5
6 Y 6
7 Y 7
8 Y 8
9 Y 9
示例 1
使整个'B'
列总和为1
,而每个子组的总和为相同的数量。这要求计算知道存在多少组。这是我们无法用 apply
做的事情,因为 apply
不知道存在多少组。
s = df.groupby('A').B.pipe(lambda g: df.B / g.transform('sum') / g.ngroups)
s
0 0.000000
1 0.083333
2 0.166667
3 0.250000
4 0.051282
5 0.064103
6 0.076923
7 0.089744
8 0.102564
9 0.115385
Name: B, dtype: float64
注意:
s.sum()
0.99999999999999989
还有:
s.groupby(df.A).sum()
A
X 0.5
Y 0.5
Name: B, dtype: float64
示例 2
从另一组的值中减去一组的平均值。同样,apply
无法做到这一点,因为 apply
不知道其他组。
df.groupby('A').B.pipe(
lambda g: (
g.get_group('X') - g.get_group('Y').mean()
).append(
g.get_group('Y') - g.get_group('X').mean()
)
)
0 -6.5
1 -5.5
2 -4.5
3 -3.5
4 2.5
5 3.5
6 4.5
7 5.5
8 6.5
9 7.5
Name: B, dtype: float64
【讨论】:
以上是关于熊猫:GroupBy .pipe() 与 .apply()的主要内容,如果未能解决你的问题,请参考以下文章