在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
功能与DataFrame对象的apply
有何不同,但对于GroupBy对象则不然。对于GroupBy,有没有人对pipe
而不是apply
有什么解释或示例?
答案 0 :(得分:19)
pipe
的作用是允许您传递一个callable,期望调用pipe
的对象是传递给callable的对象。
使用apply
,我们假设调用apply
的对象具有子组件,每个子组件都会传递给传递给apply
的可调用对象。在groupby
的上下文中,子组件是调用groupby
的数据帧的片段,其中每个片段本身就是数据帧。这与系列groupby
类似。
pipe
上下文中groupby
所能做的事情之间的主要区别在于,您可以调用groupby
对象的整个范围。对于apply,您只知道本地切片。
<强>设置强>
考虑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