Pandas groupby on multi-columns并将结果广播到原始数据帧

时间:2017-08-10 04:07:00

标签: python pandas pandas-groupby

我有一个形式为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

我想将这个df分组给'bowler'和# ' inning'并对'wickets'进行一些计算。和球#&39;球列,然后将其广播到与新列相同的df。 其中一种方法,我试图使用变换,如:

df_bowler['strike rate'] = df_bowler.groupby(['bowler','inning']).transform(lambda x : x['balls']/x['wickets'])

这会导致keyError异常:

  

KeyError :('球','发生在索引小门')

我通过使用apply然后合并完成了我所需要的,例如:

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'])

然而,这似乎是一种迂回的方式。我想知道为什么转换在这种情况下失败了。有什么指针吗?

感谢。

3 个答案:

答案 0 :(得分:2)

您的转换失败,因为您沿着错误的轴应用它,并且您需要首先使用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

答案 1 :(得分:1)

如果[]中未定义的列第一次与每个Series一起使用,则会出现问题GroupBy.transform函数 - 因此无法将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)

答案 2 :(得分:0)

编辑:

使用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的第二个选项。