pandas:GroupBy .pipe() 与 .apply()
pandas: GroupBy .pipe() vs .apply()
在 pandas documentation 关于 GroupBy 对象的新 .pipe()
方法的示例中,接受相同 lambda 的 .apply()
方法会 return 相同的结果。
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 对象。有没有人解释或举例说明 pipe
可以为 GroupBy 使用 apply
可以做什么?
pipe
的作用是允许您传递可调用对象,并期望调用 pipe
的对象是传递给可调用对象的对象。
对于 apply
,我们假设调用 apply
的对象具有子组件,每个子组件都将传递给传递给 apply
的可调用对象。在 groupby
的上下文中,子组件是称为 groupby
的数据帧的切片,其中每个切片本身就是一个数据帧。这类似于一个系列 groupby
.
在 groupby
上下文中使用 pipe
可以执行的操作之间的主要区别在于,您可以调用 groupby
对象的整个范围。对于apply,你只知道local slice。
设置
考虑 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
print(df.groupby(['A'])['B'].apply(lambda l: l/l.sum()/df.A.nunique()))
在 pandas documentation 关于 GroupBy 对象的新 .pipe()
方法的示例中,接受相同 lambda 的 .apply()
方法会 return 相同的结果。
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 对象。有没有人解释或举例说明 pipe
可以为 GroupBy 使用 apply
可以做什么?
pipe
的作用是允许您传递可调用对象,并期望调用 pipe
的对象是传递给可调用对象的对象。
对于 apply
,我们假设调用 apply
的对象具有子组件,每个子组件都将传递给传递给 apply
的可调用对象。在 groupby
的上下文中,子组件是称为 groupby
的数据帧的切片,其中每个切片本身就是一个数据帧。这类似于一个系列 groupby
.
在 groupby
上下文中使用 pipe
可以执行的操作之间的主要区别在于,您可以调用 groupby
对象的整个范围。对于apply,你只知道local slice。
设置
考虑 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
print(df.groupby(['A'])['B'].apply(lambda l: l/l.sum()/df.A.nunique()))