我有以下数据框:
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
谢谢您的帮助。
答案 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