pandas,将多列的多个函数应用于groupby对象

joh*_*tis 13 python group-by dataframe pandas

我想将多列的多个函数应用于groupby对象,从而产生一个新的pandas.DataFrame.

我知道如何以单独的步骤做到这一点:

by_user = lasts.groupby('user')
elapsed_days = by_user.apply(lambda x: (x.elapsed_time * x.num_cores).sum() / 86400)
running_days = by_user.apply(lambda x: (x.running_time * x.num_cores).sum() / 86400)
user_df = elapsed_days.to_frame('elapsed_days').join(running_days.to_frame('running_days'))
Run Code Online (Sandbox Code Playgroud)

结果user_df是: user_df

但是我怀疑有更好的方法,比如:

by_user.agg({'elapsed_days': lambda x: (x.elapsed_time * x.num_cores).sum() / 86400, 
             'running_days': lambda x: (x.running_time * x.num_cores).sum() / 86400})
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为AFAIK agg()可以工作pandas.Series.

我确实找到了这个问题和答案,但解决方案看起来相当丑陋,考虑到答案已接近四年,现在可能有更好的方法.

zth*_*.nc 6

该解决方案的另一个重要变化是使用@MaxU 对此解决方案执行类似问题并将各个函数包装在Pandas系列中,因此只需要reset_index()返回数据帧.

首先,定义转换函数:

def ed(group):
    return group.elapsed_time * group.num_cores).sum() / 86400

def rd(group):
    return group.running_time * group.num_cores).sum() / 86400
Run Code Online (Sandbox Code Playgroud)

使用以下方法将它们包装在一个系列中get_stats:

def get_stats(group):
    return pd.Series({'elapsed_days': ed(group),
                      'running_days':rd(group)})
Run Code Online (Sandbox Code Playgroud)

最后:

lasts.groupby('user').apply(get_stats).reset_index()
Run Code Online (Sandbox Code Playgroud)


jez*_*ael 5

我认为你能避免aggapply与第一,而通过多次mul,然后div和最后使用groupbyindexaggregating sum:

lasts = pd.DataFrame({'user':['a','s','d','d'],
                   'elapsed_time':[40000,50000,60000,90000],
                   'running_time':[30000,20000,30000,15000],
                   'num_cores':[7,8,9,4]})

print (lasts)
   elapsed_time  num_cores  running_time user
0         40000          7         30000    a
1         50000          8         20000    s
2         60000          9         30000    d
3         90000          4         15000    d
Run Code Online (Sandbox Code Playgroud)
by_user = lasts.groupby('user')
elapsed_days = by_user.apply(lambda x: (x.elapsed_time * x.num_cores).sum() / 86400)
print (elapsed_days)
running_days = by_user.apply(lambda x: (x.running_time * x.num_cores).sum() / 86400)
user_df = elapsed_days.to_frame('elapsed_days').join(running_days.to_frame('running_days'))
print (user_df)
      elapsed_days  running_days
user                            
a         3.240741      2.430556
d        10.416667      3.819444
s         4.629630      1.851852
Run Code Online (Sandbox Code Playgroud)
lasts = lasts.set_index('user')
print (lasts[['elapsed_time','running_time']].mul(lasts['num_cores'], axis=0)
                                             .div(86400)
                                             .groupby(level=0)
                                             .sum())
      elapsed_time  running_time
user                            
a         3.240741      2.430556
d        10.416667      3.819444
s         4.629630      1.851852   
Run Code Online (Sandbox Code Playgroud)