GroupByオブジェクトの新しい.pipe()
メソッドに関する pandasドキュメント の例では、同じラムダを受け入れる.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
DataFrameオブジェクトのpipe
機能がapply
とどのように異なるかがわかりますが、GroupByオブジェクトの場合は違います。 GroupByのpipe
ではなくapply
ではできないことの説明や例はありますか?
pipe
が行うことは、pipe
を呼び出したオブジェクトがcallableに渡されるオブジェクトであるという期待でcallableを渡すことを可能にすることです。
apply
では、apply
を呼び出すオブジェクトに、apply
に渡された呼び出し可能オブジェクトにそれぞれ渡されるサブコンポーネントがあると想定しています。 groupby
のコンテキストでは、サブコンポーネントはgroupby
と呼ばれるデータフレームのスライスであり、各スライスはデータフレーム自体です。これはシリーズgroupby
に似ています。
pipe
コンテキストでgroupby
を使用してできることの主な違いは、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