根据条件对数据帧行进行分组和平均

时间:2020-06-12 15:33:05

标签: python pandas dataframe

我有以下数据框:

Company_ID  Year   Metric_1  Metric_2  Bankrupt
1           2010   10        20        0.0
1           2011   NaN       30        0.0
1           2012   30        40        0.0
1           2013   50        NaN       1.0
2           2012   50        60        0.0
2           2013   60        NaN       0.0
2           2014   10        10        0.0
3           2011   100       100       1.0

我想为每个公司做除过去一年以外所有年份所有指标的平均值。它仅应取当前值的平均值,而忽略缺失值(NaN)。同样,它不应该平均破产列。

因此输出应如下所示:

Company_ID  Year        Metric_1  Metric_2  Bankrupt
1           2010-2012   20        30        0.0
1           2013        50        Nan       1.0
2           2012-2013   55        60        0.0
2           2014        10        10        0.0
3           2011        100       100       1.0

谢谢您的帮助。

3 个答案:

答案 0 :(得分:4)

m = df.Bankrupt.eq(0) & df.groupby('Company_ID').Year.transform(lambda x: x != x.max())
df[m].groupby(['Company_ID','Bankrupt']).agg(Year=('Year', lambda x: f'{x.min()}-{x.max()}'),
    Metric_1=('Metric_1', 'mean'),
    Metric_2=('Metric_2', 'mean')).reset_index().append(df[~m]).sort_values('Company_ID')

结果:

    Company_ID  Bankrupt       Year  Metric_1  Metric_2
0           1       0.0  2010-2012      20.0      30.0
3           1       1.0       2013      50.0       NaN
1           2       0.0  2012-2013      55.0      60.0
6           2       0.0       2014      10.0      10.0
7           3       1.0       2011     100.0     100.0

答案 1 :(得分:4)

这种方法类似于@Stef的方法,但我保留了这一方法,因为它适用于任意数量的Metric列(只要它们的名称以Metric开头)。如果最终使用此解决方案,请改为接受他们的解决方案。

您可以这样做

#mask for catching last year per Company
m = df.groupby(['Company_ID'])['Year'].transform('max').eq(df['Year'])
# create groups per company without the last year
gr = df[~m].groupby(df['Company_ID'], as_index=False)

df_ = (pd.concat([gr.agg(Company_ID=('Company_ID', 'first'), #perform agg depending on needs
                         Bankrupt=('Bankrupt', 'first'), #here I'm not sure with value you want
                         Year=('Year', lambda x: f'{x.min()}-{x.max()}')), 
                  gr[df.filter(like='Metric').columns].mean()], 
                 axis=1)
         .append(df[m]) # append last year
         .sort_values(['Company_ID'])
         .reset_index(drop=True)
      )
print (df_)   
   Company_ID  Bankrupt       Year  Metric_1  Metric_2
0           1       0.0  2010-2012      20.0      30.0
1           1       1.0       2013      50.0       NaN
2           2       0.0  2012-2013      55.0      60.0
3           2       0.0       2014      10.0      10.0
4           3       1.0       2011     100.0     100.0

另一个避免使用append和sort_values的版本,您可以对Year列使用不同的lambda函数来实现

#mask for catching last year per Company
m = df.groupby(['Company_ID'])['Year'].transform('max').eq(df['Year']) #same
# create groups per company without the last year
gr = df.groupby([df['Company_ID'], m]) #m is in the groupby and not as mask

df_ = (pd.concat([gr.agg(Company_ID=('Company_ID', 'first'), 
                        Bankrupt=('Bankrupt', 'first'),
                        Year=('Year', lambda x: f'{x.min()}-{x.max()}' if x.min()!=x.max()
                                                else x.max())), #different lambda function
                  gr[df.filter(like='Metric').columns].mean()], 
                 axis=1)
         #no more append/sort_values
         .reset_index(drop=True)
      )

答案 2 :(得分:2)

另一种方法,与其他方法非常相似,但有一个附加组且没有面具:

#helper group
g = df.groupby(['Company_ID'])['Year'].transform(lambda x: (x.max()==x).cumsum())
#helper function
f = lambda x: f"{x.min()}-{x.max()}" if len(set(x))>1 else x

(df.groupby(['Company_ID',g]).agg({'Year':f,'Metric_1':'mean','Metric_2':'mean',
 'Bankrupt':'first'}).droplevel(1).reset_index())

   Company_ID       Year  Metric_1  Metric_2  Bankrupt
0           1  2010-2012      20.0      30.0       0.0
1           1       2013      50.0       NaN       1.0
2           2  2012-2013      55.0      60.0       0.0
3           2       2014      10.0      10.0       0.0
4           3       2011     100.0     100.0       1.0