Pandas 在多列上分组并将结果广播到原始数据帧
Pandas groupby on multi-columns and broadcast the result to the original dataframe
我有一个 pandas 形式的数据框:
bowler inning wickets Total_wickets matches balls
0 SL Malinga 1 69 143 44 4078
1 SL Malinga 2 74 143 54 4735
2 A Mishra 1 48 124 50 3908
3 A Mishra 2 76 124 62 4930
4 DJ Bravo 1 61 122 48 3887
我想在 'bowler' 和 'inning' 上对这个 df 进行分组,并在 'wickets' 和 'balls' 列上执行一些计算,然后将它广播到相同的 df 作为新专栏。
我尝试的其中一种方法是使用转换,例如:
df_bowler['strike rate'] = df_bowler.groupby(['bowler','inning']).transform(lambda x : x['balls']/x['wickets'])
这会导致 keyError 异常:
KeyError: ('balls', 'occurred at index wickets')
我通过使用 apply 和 merge 完成了我需要的,例如:
df_strRate = df_bowler.groupby(['bowler','inning']).apply(lambda x:x['balls']/x['wickets']).reset_index(level=2,drop=True).reset_index(name='strike rate')
df_bowler = df_bowler.merge(df_strRate,on=['bowler','inning'])
但是,这似乎是一种迂回的做法。我想知道为什么在这种情况下转换失败。有什么指点吗?
谢谢。
您的转换失败,因为您沿错误的轴应用它,您需要先使用 sum()
等聚合。看看这个:
In [83]: df.groupby(['bowler', 'inning']).sum().transform(lambda x : x['balls'].astype(float)/x['wickets'].astype(float), axis=1)
Out[83]:
bowler inning
A Mishra 1 81.416667
2 64.868421
DJ Bravo 1 63.721311
SL Malinga 1 59.101449
2 63.986486
dtype: float64
但你也可以这样做:
In [88]: df['strike_rate'] = df.balls / df.wickets
In [89]: df
Out[89]:
bowler inning wickets Total_wickets matches balls strike_rate
0 SL Malinga 1 69 143 44 4078 59.101449
1 SL Malinga 2 74 143 54 4735 63.986486
2 A Mishra 1 48 124 50 3908 81.416667
3 A Mishra 2 76 124 62 4930 64.868421
4 DJ Bravo 1 61 122 48 3887 63.721311
编辑:
尝试使用以下方法使用 apply()
df = df.merge(df.groupby(['bowler', 'inning']).apply(lambda x : sum(x['balls']/x['wickets')]).reset_index(), on=['bowler', 'inning']).rename(columns={0:'Mycolumn'})
#If you don't want a rename then new resulted column will be named as 0. As per your wish, use it/discard rename part.
或者,如果您想要简单的列操作,我更喜欢 Cory 的第二个选项。
如果 []
中未定义列,则函数存在问题 GroupBy.transform
首先分别处理每个 Series
- 因此无法同时处理 2 列,不可能将它们分开:
def f(x):
print (x)
2 48
Name: wickets, dtype: int64
2 124
Name: Total_wickets, dtype: int64
2 50
Name: matches, dtype: int64
2 3908
Name: balls, dtype: int64
df = df_bowler.groupby(['bowler','inning']).transform(f)
如果在 []
中定义列:
def f(x):
print (x)
2 3908
Name: (A Mishra, 1), dtype: int64
3 4930
Name: (A Mishra, 2), dtype: int64
4 3887
Name: (DJ Bravo, 1), dtype: int64
0 4078
Name: (SL Malinga, 1), dtype: int64
1 4735
Name: (SL Malinga, 2), dtype: int64
df = df_bowler.groupby(['bowler','inning'])['balls'].transform(f)
DataFrameGroupBy.agg
函数的工作方式相同。
结论:
如果想按组处理数据需要GroupBy.apply
:
def f(x):
print (x)
bowler inning wickets Total_wickets matches balls
2 A Mishra 1 48 124 50 3908
bowler inning wickets Total_wickets matches balls
2 A Mishra 1 48 124 50 3908
bowler inning wickets Total_wickets matches balls
3 A Mishra 2 76 124 62 4930
bowler inning wickets Total_wickets matches balls
df = df_bowler.groupby(['bowler','inning']).apply(f)
我有一个 pandas 形式的数据框:
bowler inning wickets Total_wickets matches balls
0 SL Malinga 1 69 143 44 4078
1 SL Malinga 2 74 143 54 4735
2 A Mishra 1 48 124 50 3908
3 A Mishra 2 76 124 62 4930
4 DJ Bravo 1 61 122 48 3887
我想在 'bowler' 和 'inning' 上对这个 df 进行分组,并在 'wickets' 和 'balls' 列上执行一些计算,然后将它广播到相同的 df 作为新专栏。 我尝试的其中一种方法是使用转换,例如:
df_bowler['strike rate'] = df_bowler.groupby(['bowler','inning']).transform(lambda x : x['balls']/x['wickets'])
这会导致 keyError 异常:
KeyError: ('balls', 'occurred at index wickets')
我通过使用 apply 和 merge 完成了我需要的,例如:
df_strRate = df_bowler.groupby(['bowler','inning']).apply(lambda x:x['balls']/x['wickets']).reset_index(level=2,drop=True).reset_index(name='strike rate')
df_bowler = df_bowler.merge(df_strRate,on=['bowler','inning'])
但是,这似乎是一种迂回的做法。我想知道为什么在这种情况下转换失败。有什么指点吗?
谢谢。
您的转换失败,因为您沿错误的轴应用它,您需要先使用 sum()
等聚合。看看这个:
In [83]: df.groupby(['bowler', 'inning']).sum().transform(lambda x : x['balls'].astype(float)/x['wickets'].astype(float), axis=1)
Out[83]:
bowler inning
A Mishra 1 81.416667
2 64.868421
DJ Bravo 1 63.721311
SL Malinga 1 59.101449
2 63.986486
dtype: float64
但你也可以这样做:
In [88]: df['strike_rate'] = df.balls / df.wickets
In [89]: df
Out[89]:
bowler inning wickets Total_wickets matches balls strike_rate
0 SL Malinga 1 69 143 44 4078 59.101449
1 SL Malinga 2 74 143 54 4735 63.986486
2 A Mishra 1 48 124 50 3908 81.416667
3 A Mishra 2 76 124 62 4930 64.868421
4 DJ Bravo 1 61 122 48 3887 63.721311
编辑:
尝试使用以下方法使用 apply()
df = df.merge(df.groupby(['bowler', 'inning']).apply(lambda x : sum(x['balls']/x['wickets')]).reset_index(), on=['bowler', 'inning']).rename(columns={0:'Mycolumn'})
#If you don't want a rename then new resulted column will be named as 0. As per your wish, use it/discard rename part.
或者,如果您想要简单的列操作,我更喜欢 Cory 的第二个选项。
如果 []
中未定义列,则函数存在问题 GroupBy.transform
首先分别处理每个 Series
- 因此无法同时处理 2 列,不可能将它们分开:
def f(x):
print (x)
2 48
Name: wickets, dtype: int64
2 124
Name: Total_wickets, dtype: int64
2 50
Name: matches, dtype: int64
2 3908
Name: balls, dtype: int64
df = df_bowler.groupby(['bowler','inning']).transform(f)
如果在 []
中定义列:
def f(x):
print (x)
2 3908
Name: (A Mishra, 1), dtype: int64
3 4930
Name: (A Mishra, 2), dtype: int64
4 3887
Name: (DJ Bravo, 1), dtype: int64
0 4078
Name: (SL Malinga, 1), dtype: int64
1 4735
Name: (SL Malinga, 2), dtype: int64
df = df_bowler.groupby(['bowler','inning'])['balls'].transform(f)
DataFrameGroupBy.agg
函数的工作方式相同。
结论:
如果想按组处理数据需要GroupBy.apply
:
def f(x):
print (x)
bowler inning wickets Total_wickets matches balls
2 A Mishra 1 48 124 50 3908
bowler inning wickets Total_wickets matches balls
2 A Mishra 1 48 124 50 3908
bowler inning wickets Total_wickets matches balls
3 A Mishra 2 76 124 62 4930
bowler inning wickets Total_wickets matches balls
df = df_bowler.groupby(['bowler','inning']).apply(f)