假设我有一个df,它的列是" ID " " col_1 " " col_2 "我定义了一个函数:

F = x, y: my_function_expression。

现在我想应用f到df的两个列'col_1', 'col_2'来逐个元素计算一个新列'col_3',有点像:

df['col_3'] = df[['col_1','col_2']].apply(f)  
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'

怎么办?

**添加详细示例如下***

import pandas as pd

df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']

def get_sublist(sta,end):
    return mylist[sta:end+1]

#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below 

  ID  col_1  col_2            col_3
0  1      0      1       ['a', 'b']
1  2      2      4  ['c', 'd', 'e']
2  3      3      5  ['d', 'e', 'f']

当前回答

你写f的方法需要两个输入。如果你看一下错误消息,它说你没有为f提供两个输入,只有一个。错误信息是正确的。 不匹配是因为df[['col1','col2']]返回一个有两列的数据帧,而不是两个独立的列。

你需要改变你的f,让它只接受一个输入,保持上面的数据帧作为输入,然后在函数体中把它分解成x,y。然后执行所需的操作并返回一个值。

你需要这个函数签名,因为语法是。apply(f) f需要取一个= dataframe的东西,而不是当前f所期望的两个东西。

由于你没有提供f的主体,我不能提供更多的细节-但这应该提供了出路,而不需要从根本上改变你的代码或使用一些其他方法而不是应用

其他回答

我相信这不会像使用Pandas或Numpy操作的解决方案那么快,但如果你不想重写你的函数,你可以使用map。使用原始示例数据-

import pandas as pd

df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']

def get_sublist(sta,end):
    return mylist[sta:end+1]

df['col_3'] = list(map(get_sublist,df['col_1'],df['col_2']))
#In Python 2 don't convert above to list

我们可以通过这种方式向函数传递任意数量的参数。输出就是我们想要的

ID  col_1  col_2      col_3
0  1      0      1     [a, b]
1  2      2      4  [c, d, e]
2  3      3      5  [d, e, f]

另一个选项是df.itertuples()(通常比df.iterrows()更快,由文档和用户测试推荐):

import pandas as pd

df = pd.DataFrame([range(4) for _ in range(4)], columns=list("abcd"))

df
    a   b   c   d
0   0   1   2   3
1   0   1   2   3
2   0   1   2   3
3   0   1   2   3


df["e"] = [sum(row) for row in df[["b", "d"]].itertuples(index=False)]

df
    a   b   c   d   e
0   0   1   2   3   4
1   0   1   2   3   4
2   0   1   2   3   4
3   0   1   2   3   4

因为itertuples返回一个namedtuples的Iterable,你可以通过列名(又名点表示法)和索引来访问元组元素:

b, d = row
b = row.b
d = row[1]

一个简单的解决方案是:

df['col_3'] = df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)

如果你有一个巨大的数据集,那么你可以使用一种简单但更快(执行时间)的方式来做到这一点,使用swifter:

import pandas as pd
import swifter

def fnc(m,x,c):
    return m*x+c

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})
df["y"] = df.swifter.apply(lambda x: fnc(x.m, x.x, x.c), axis=1)

在Pandas中有一个简单的方法:

df['col_3'] = df.apply(lambda x: f(x.col_1, x.col_2), axis=1)

这允许f是一个用户定义的具有多个输入值的函数,并使用(安全的)列名而不是(不安全的)数字索引来访问列。

数据示例(基于原始问题):

import pandas as pd

df = pd.DataFrame({'ID':['1', '2', '3'], 'col_1': [0, 2, 3], 'col_2':[1, 4, 5]})
mylist = ['a', 'b', 'c', 'd', 'e', 'f']

def get_sublist(sta,end):
    return mylist[sta:end+1]

df['col_3'] = df.apply(lambda x: get_sublist(x.col_1, x.col_2), axis=1)

打印输出(df):

  ID  col_1  col_2      col_3
0  1      0      1     [a, b]
1  2      2      4  [c, d, e]
2  3      3      5  [d, e, f]

如果你的列名包含空格或与现有的dataframe属性共享一个名称,你可以用方括号索引:

df['col_3'] = df.apply(lambda x: f(x['col 1'], x['col 2']), axis=1)