【问题标题】:Applying function with multiple arguments to create a new pandas column应用具有多个参数的函数来创建一个新的 pandas 列
【发布时间】:2013-11-23 18:16:27
【问题描述】:

我想通过将函数应用于两个现有列来在 pandas 数据框中创建一个新列。在此answer 之后,当我只需要一列作为参数时,我已经能够创建一个新列:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})

def fx(x):
    return x * x

print(df)
df['newcolumn'] = df.A.apply(fx)
print(df)

但是,当函数需要多个参数时,我无法弄清楚如何做同样的事情。例如,如何通过将 A 列和 B 列传递给下面的函数来创建新列?

def fxy(x, y):
    return x * y

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    如果您可以重写您的函数,您可以使用@greenAfrican 示例。但是如果你不想重写你的函数,你可以把它包装到apply里面的匿名函数中,像这样:

    >>> def fxy(x, y):
    ...     return x * y
    
    >>> df['newcolumn'] = df.apply(lambda x: fxy(x['A'], x['B']), axis=1)
    >>> df
        A   B  newcolumn
    0  10  20        200
    1  20  30        600
    2  30  10        300
    

    【讨论】:

    • 这是一个很棒的技巧,它将列引用留在 apply 调用附近(实际上在其中)。我使用这个技巧和提供的多列输出技巧@toto_tico 来生成一个 3 列输入,4 列输出函数!效果很好!
    • 哇,看来您是唯一一个不关注 OP 的最小示例但解决了整个问题的人,谢谢,正是我需要的! :)
    • 确实这应该是“官方”的答案。
    【解决方案2】:

    或者,您可以使用 numpy 底层函数:

    >>> import numpy as np
    >>> df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
    >>> df['new_column'] = np.multiply(df['A'], df['B'])
    >>> df
        A   B  new_column
    0  10  20         200
    1  20  30         600
    2  30  10         300
    

    或者一般情况下对任意函数进行矢量化:

    >>> def fx(x, y):
    ...     return x*y
    ...
    >>> df['new_column'] = np.vectorize(fx)(df['A'], df['B'])
    >>> df
        A   B  new_column
    0  10  20         200
    1  20  30         600
    2  30  10         300
    

    【讨论】:

    • 感谢您的回答!我很好奇,这是最快的解决方案吗?
    • 使用np.vectorize() 的矢量化版本速度惊人。谢谢。
    • 这是一个有用的解决方案。如果函数 x 和 y 的输入参数的大小不相等,则会出现错误。在这种情况下,@RomanPekar 解决方案可以正常工作。我没有比较性能。
    • 我知道这是一个旧答案,但是:我有一个极端情况,np.vectorize 不起作用。原因是,其中一列是pandas._libs.tslibs.timestamps.Timestamp 类型,通过矢量化变成numpy.datetime64 类型。这两种类型不可互换,导致函数表现不佳。对此有何建议? (.apply 除外,因为这显然是要避免的)
    • 很好的解决方案!万一有人想知道矢量化对于字符串比较函数也能很好地工作并且超快。
    【解决方案3】:

    这样就解决了问题:

    df['newcolumn'] = df.A * df.B
    

    你也可以这样做:

    def fab(row):
      return row['A'] * row['B']
    
    df['newcolumn'] = df.apply(fab, axis=1)
    

    【讨论】:

    • 这个答案解决了这个玩具示例,足以让我重写我的实际函数,但它没有解决如何应用先前定义的函数而不将其重写为引用列。
    • 请注意,矢量化操作(第一个代码示例)比apply 的代码示例具有更好的性能。
    【解决方案4】:

    如果您需要一次创建多个列

    1. 创建数据框:

      import pandas as pd
      df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]})
      
    2. 创建函数:

      def fab(row):                                                  
          return row['A'] * row['B'], row['A'] + row['B']
      
    3. 分配新列:

      df['newcolumn'], df['newcolumn2'] = zip(*df.apply(fab, axis=1))
      

    【讨论】:

    • 我想知道如何通过一个应用生成多个列!我将此与@Roman Pekar 的答案一起使用以生成一个 3 列输入,4 列输出函数!效果很好!
    • 你能解释一下zip在这里做什么吗?谢谢!
    • zip 迭代同时几个可迭代对象(例如列表、迭代器)。 *df.apply 将产生 N (N=len(df)) 可迭代对象,每个可迭代对象包含 2 个元素; zip 将同时迭代 N 行,因此它会产生 2 个可迭代的 N 个元素。您可以对此进行测试,例如zip(['a','b'],['c','d'],['e','f']) 将产生 [('a', 'c', 'e'), ('b', 'd', 'f')] (基本上是转置)。请注意,我有意使用 yield 这个词,而不是 return,因为我们正在谈论迭代器(因此,将 zip 结果转换为列表:list(zip(['a','b'],['c','d'],['e','f']))
    【解决方案5】:

    另一种 dict 风格的简洁语法:

    df["new_column"] = df.apply(lambda x: x["A"] * x["B"], axis = 1)
    

    或者,

    df["new_column"] = df["A"] * df["B"]
    

    【讨论】:

      【解决方案6】:

      def fx(a, b): ... 返回 a*b ... df['new_col'] = np.vectorize(fx)(df['A'], df['B']) df A B 新列 0 10 30 200 1 10 40 400 2 10 50 500

      【讨论】:

      • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 2017-06-17
      • 2019-01-02
      • 2018-06-07
      • 2020-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-17
      相关资源
      最近更新 更多