【问题标题】:Python Pandas: Apply function using column names as named argumentsPython Pandas:使用列名作为命名参数应用函数
【发布时间】:2019-10-18 16:44:36
【问题描述】:

pandas 中是否有一种方法可以使用列名作为参数名将函数应用于数据框?例如,我有一个函数和一个数据框。

df = pd.DataFrame({'A':[1,2,3],
               'B':[1,2,3],
               'C':[1,2,3],
               'D':[1,2,3]})    
def f(A,B,C):
   #Pretend code is more complicated
   return A + B + C

有没有办法让我做类似的事情

df.apply(f)

让 pandas 将列与命名参数匹配?

我知道我可以重写函数以获取一行而不是命名参数,但请记住 f 只是一个玩具示例,我的实际函数更复杂

编辑:

根据@juanpa.arrivillaga 的答案想出来:

df[list(f.__code__.co_varnames)].apply((lambda row: f(**row)), axis=1)

【问题讨论】:

  • ?df.eval('A+B+C')
  • 有没有办法做到这一点而不必重写函数 f?
  • 函数 f 只是一个玩具示例。我的真正功能更复杂。
  • 明确地使用示例函数可能更有帮助。
  • 现在,您的 apply 正在按列执行。在这种情况下,将它传递给你所拥有的系列更为合乎逻辑。您可以按行进行操作,但老实说,在大多数情况下,您可以避免使用 apply 循环以支持矢量化操作。

标签: python pandas dataframe apply


【解决方案1】:

应用f 的函数需要根据axis=0,1df 接受行/列作为参数,而不是列名。为此,您可以编写一个包装器。

def wrapper(x, A, B, C):
    return f(x[A], x[B], x[C])

df.apply(wrapper, axis=1, args=('A','B','C'))

输出:

0    3
1    6
2    9
dtype: int64

【讨论】:

    【解决方案2】:

    如果你对“应用”功能感兴趣,这里就是这样

    df = pd.DataFrame({'A':[1,2,3],
                      'B':[1,2,3],
                      'C':[1,2,3],
                      'D':[1,2,3]})     
    
    
    def func(row):
        row['result'] = row['A'] + row['B'] + row['C']
        return row
    
    df.apply(func, axis = 1)
    
    
        Out[67]: 
           A  B  C  D  result
        0  1  1  1  1       3
        1  2  2  2  2       6
        2  3  3  3  3       9
    

    更新

    如果你必须使用函数“f”并且不想改变它,可能是这样的:

    df['res'] = f(df['A'], df['B'], df['C'])
    df
    
        Out[70]: 
           A  B  C  D  res
        0  1  1  1  1    3
        1  2  2  2  2    6
        2  3  3  3  3    9
    

    【讨论】:

    • 这行得通,但是有没有办法在不必重写函数 f 的情况下做到这一点?
    • 这很有效,而且很简单,所以赞成!但通常大多数函数都不能对序列进行操作,尤其是我的真正函数中有 if 语句。
    【解决方案3】:

    没有什么好办法一般来说。但是,如果您的列名完全正确,您可以将函数包装在另一个函数中,该函数将行参数添加到您的函数中,因为Series 对象是映射!

    所以给定:

    >>> import pandas as pd
    >>> df = pd.DataFrame({'A':[1,2,3],
    ...                'B':[1,2,3],
    ...                'C':[1,2,3],
    ...                'D':[1,2,3]})
    >>> df
       A  B  C  D
    0  1  1  1  1
    1  2  2  2  2
    2  3  3  3  3
    >>> def f(A, B, C): return A + B + C
    ...
    

    我们可以几乎做到:

    >>> df.apply(lambda row: f(**row), axis=1)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/Users/juan/anaconda3/envs/ecqm-catalog/lib/python3.7/site-packages/pandas/core/frame.py", line 6014, in apply
        return op.get_result()
      File "/Users/juan/anaconda3/envs/ecqm-catalog/lib/python3.7/site-packages/pandas/core/apply.py", line 142, in get_result
        return self.apply_standard()
      File "/Users/juan/anaconda3/envs/ecqm-catalog/lib/python3.7/site-packages/pandas/core/apply.py", line 248, in apply_standard
        self.apply_series_generator()
      File "/Users/juan/anaconda3/envs/ecqm-catalog/lib/python3.7/site-packages/pandas/core/apply.py", line 277, in apply_series_generator
        results[i] = self.f(v)
      File "<stdin>", line 1, in <lambda>
    TypeError: ("f() got an unexpected keyword argument 'D'", 'occurred at index 0')
    

    如果您知道您需要哪些列,您可以选择/删除以获得正确的系列:

    >>> df.drop('D',axis=1).apply(lambda row: f(**row), axis=1)
    0    3
    1    6
    2    9
    

    【讨论】:

    • 是的,我把 D 列扔进去了,因为通常会有额外的列。不过,我喜欢 ** 的把戏
    【解决方案4】:

    想通了,建立在@juanpa.arrivillaga 答案的基础上。

    df[list(f.__code__.co_varnames)].apply((lambda row: f(**row)), axis=1)

    【讨论】:

      猜你喜欢
      • 2023-02-01
      • 2015-07-03
      • 2021-06-24
      • 1970-01-01
      • 2013-03-31
      • 2010-10-04
      • 2012-11-05
      • 2022-01-16
      相关资源
      最近更新 更多