pandas:GroupBy .pipe()vs .apply()

时间:2017-11-10 15:41:13

标签: python python-3.x pandas pandas-groupby

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有什么解释或示例?

1 个答案:

答案 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