使用apply时如何将数据框的所有列传递给函数?

How to pass all columns of a dataframe to a function when using apply?

我有一个包含多个列的 pandas 数据框,例如

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(0,100,size=(100, 7)), columns=list('ABCDEFG'))

我想 apply 一个可以接受数据框所有列作为参数的函数:

# function would do something more complex potentially :)
def foo(a,b,c,d,e,f,g):
  # do stuff with a,b,c,d,e,f,g. Here I do something silly/simple
  return a + b*2 + c*3 + d*4 + e*5 + f*5 + g*5

现在,我想将 foo 应用于 df 的所有行。这样做的正确语法是什么?

我的尝试成功了

df.apply(lambda row: foo(row[0], row[1], row[2], row[3], row[4], row[5], row[6]), axis = 1) # terrible
df.apply(lambda row: foo(*row), axis = 1) #  better

但是有没有办法更简洁地做到这一点,例如没有 lambda?

对功能进行简单调整即可解决问题

def foo(a=df['A'],b=df['B'],c=df['C'],d=df['D'],e=df['E'],f=df['F'],g=df['G']):
    return a + b*2 + c*3 + d*4 + e*5 + f*5 + g*5

df.apply(foo)

       A     B     C     D     E     F     G
0    755   731   736   745   717   696   697
1   1365  1330  1321  1323  1332  1348  1367
2    985  1002   971   982  1012  1017  1052
3   1078  1016  1094  1034  1034  1049  1102
4   1045  1059  1041  1101  1100  1025  1041
..   ...   ...   ...   ...   ...   ...   ...
95  1318  1338  1341  1349  1357  1356  1358
96  1323  1387  1349  1321  1315  1370  1389
97  1066  1101  1057  1098  1132  1078  1067
98  1261  1229  1273  1312  1283  1296  1231
99  1585  1522  1537  1590  1591  1558  1548

[100 rows x 7 columns]

更新

df.apply(lambda x: x['A'] + x['B']*2 + x['C']*3 + x['D']*4 + x['E']*5 + x['F']*5 + x['G']*5,1)

0      755
1     1365
2      985
3     1078
4     1045
      ... 
95    1318
96    1323
97    1066
98    1261
99    1585
Length: 100, dtype: int64

这是一种将数据帧的所有列传递给函数 而不使用应用或 lambda 的方法。

foo(*df.to_numpy().T)

那 return 是一个 numpy 数组。如果你需要它 return 一个 pandas 与输入具有相同索引的系列,你可以这样做:

 pd.Series(foo(*df.to_numpy().T), index=df.index)

事实证明它比 lambda 方法快得多(至少对我来说 运行 python 3.5)。

>>> import timeit
>>> timeit.timeit("df.apply(lambda row: foo(*row), axis = 1)", setup="from __main__ import foo, df", number=10)    
0.028233799999981102
>>> timeit.timeit("pd.Series(foo(*df.to_numpy().T), index=df.index)", setup="from __main__ import foo, df, pd", number=10)
0.0019406999999773689
>>> timeit.timeit("foo(*df.to_numpy().T)", setup="from __main__ import foo, df", number=10)                        
0.0004090000000189775

当 return 使用 numpy 数组时速度提高 69 倍,当 return 使用 pandas 系列并保持索引时速度提高 15 倍!