ChatGPT解决这个技术问题 Extra ChatGPT

应用具有多个参数的函数来创建一个新的 pandas 列

我想通过将函数应用于两个现有列来在 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

R
Roman Pekar

如果您可以重写您的函数,您可以使用@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 的最小示例但解决了整个问题的人,谢谢,正是我所需要的! :)
事实上,这应该是“官方”的答案。
a
alko

或者,您可以使用 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,因为这显然是要避免的)
很好的解决方案!万一有人想知道矢量化对于字符串比较函数也能很好地工作并且超级快。
g
greenafrican

这解决了问题:

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

你也可以这样做:

def fab(row):
  return row['A'] * row['B']

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

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

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

创建数据框: import pandas as pd df = pd.DataFrame({"A": [10,20,30], "B": [20, 30, 10]}) 创建函数: def fab(row): return row['A'] * row['B'], row['A'] + row['B'] 分配新列:df['newcolumn'], df['newcolumn2'] = zip(* df.apply(fab, 轴=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']))
S
Surya

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

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

或者,

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

A
Ayeni Lawrence

这将动态地为您提供所需的结果。即使您有两个以上的参数,它也有效

df['anothercolumn'] = df[['A', 'B']].apply(lambda x: fxy(*x), axis=1)
print(df)


    A   B  newcolumn  anothercolumn
0  10  20        100            200
1  20  30        400            600
2  30  10        900            300