我想通过将函数应用于两个现有列来在 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
如果您可以重写您的函数,您可以使用@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
或者,您可以使用 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()
的矢量化版本速度惊人。谢谢你。
np.vectorize
不起作用。原因是,其中一列是 pandas._libs.tslibs.timestamps.Timestamp
类型,它通过矢量化变成了 numpy.datetime64
类型。这两种类型不可互换,导致函数表现不佳。对此有何建议? (除了 .apply
,因为这显然是要避免的)
这解决了问题:
df['newcolumn'] = df.A * df.B
你也可以这样做:
def fab(row):
return row['A'] * row['B']
df['newcolumn'] = df.apply(fab, axis=1)
apply
的代码示例具有更好的性能。
如果您需要一次创建多个列:
创建数据框: 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))
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']))
)
另一种 dict 风格的简洁语法:
df["new_column"] = df.apply(lambda x: x["A"] * x["B"], axis = 1)
或者,
df["new_column"] = df["A"] * df["B"]
这将动态地为您提供所需的结果。即使您有两个以上的参数,它也有效
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