【问题标题】:How to pass all columns of a dataframe to a function when using apply?使用apply时如何将数据框的所有列传递给函数?
【发布时间】:2020-02-04 10:43:45
【问题描述】:

我有一个包含几列的 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

【问题讨论】:

  • 如果您的函数中的参数与您的 col 名称匹配,您可以创建一个 dict,然后迭代它会减少代码。你也可以压缩两个迭代器,并应用函数直到迭代器结束。
  • 为什么要在这里使用apply? stackoverflow.com/questions/54432583/…

标签: python pandas idioms


【解决方案1】:

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

foo(*df.to_numpy().T)

返回一个 numpy 数组。如果您需要它返回与输入具有相同索引的熊猫系列,您可以这样做:

 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

返回 numpy 数组时速度快 69 倍,返回 pandas Series 并保留索引时速度快 15 倍!

【讨论】:

    【解决方案2】:

    对功能进行简单的调整就可以解决问题

    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
    

    【讨论】:

    • 谢谢,但是......在我的示例中,预期结果是一系列 len(100) ! (注意axis = 1传递给apply,结果逐行馈送)
    • 我已经更新了一个更简单的版本..在您的情况下,需要一个循环,因为您需要单独的值并希望对其执行操作..无法想象任何其他方式..介意我也可能是错的。
    • df.mul(pd.Series(data = [1,2,3,4,5,5,5],index = df.columns)).sum(axis = 1)
    • @ansev 这个想法是要有一个有很多参数的函数,而不是简单地乘以列值,我会让这个问题更笼统......
    猜你喜欢
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 2019-08-12
    • 1970-01-01
    相关资源
    最近更新 更多