Python Pandas:对Series应用带参数的函数

243

我想在Python Pandas中将一个带参数的函数应用于一个Series:

x = my_series.apply(my_function, more_arguments_1)
y = my_series.apply(my_function, more_arguments_2)
...

文档中支持 apply 方法,但它不接受任何参数。有没有接受参数的其他方法?或者说,我是否错过了一个简单的解决方法?

更新(2017年10月):请注意,自此问题最初提出以来,pandas 的apply()已经更新,可以处理位置和关键字参数,上面的文档链接也反映了这一点,并展示了如何包括这两种类型的参数。


3
为什么不直接使用 functools.partialstarmap - Joel Cornett
1
请参阅DataFrame.apply文档Series.apply文档 - Martin Thoma
7个回答

274

较新版本的pandas确实允许您传递额外的参数(请参见新文档)。因此,现在您可以执行以下操作:

my_series.apply(your_function, args=(2,3,4), extra_kw=1)

序列的元素之后添加位置参数。


对于较旧版本的pandas:

文档清楚地解释了这一点。apply方法接受一个Python函数,该函数应该有一个单一参数。如果你想传递更多参数,可以像Joel Cornett在他的评论中建议的那样使用functools.partial。

一个例子:

>>> import functools
>>> import operator
>>> add_3 = functools.partial(operator.add,3)
>>> add_3(2)
5
>>> add_3(7)
10

你也可以使用partial传递关键字参数。

另一种方式是创建一个lambda函数:

my_series.apply((lambda x: your_func(a,b,c,d,...,x)))

但我认为使用partial更好。


14
对于DataFrame的apply方法,接受一个名为args的参数,它是一个元组,保存附加的位置参数或者命名关键字参数。我提了一个问题,希望也能将此功能添加到Series.apply()中。具体请见:https://github.com/pydata/pandas/issues/1829 - Wouter Overmeire
31
功能已经实现,将在即将发布的pandas版本中推出。 - Wes McKinney
4
这是一个很好的回答,但前三分之二现在已经过时了。我的看法是,只需将此回答更新为指向新文档的链接,并简要介绍如何使用位置参数和/或关键字参数即可。这只是提供信息,并非对原始答案的批评,但我认为更新会更有益,特别是因为这是一个经常被阅读的答案。 - JohnE
@watsonic,文档已经更新,点击旧链接会跳转到最新的文档,其中已经很好地回答了这个问题。 - JohnE
8
注意:如果您传递单个字符串参数,例如 'abc',那么 args=('abc') 将被解释为包含三个字符的元组 ('a', 'b', 'c')。为了避免这种情况发生,您必须传递包含该字符串的元组,并且为此,请在末尾添加一个逗号:args=('abc',) - Rocky K
显示剩余2条评论

141

步骤:

  1. 创建数据框。
  2. 创建函数。
  3. 在 apply 语句中使用函数的命名参数。

示例

x=pd.DataFrame([1,2,3,4])  

def add(i1, i2):  
    return i1+i2

x.apply(add,i2=9)

这个示例的结果是,数据框中的每个数字都将被加上9。

    0
0  10
1  11
2  12
3  13

解释:

"add"函数有两个参数:i1和i2。第一个参数将是数据框中的值,第二个参数是我们传递给"apply"函数的任何值。在本例中,我们使用关键字参数"i2"将"9"传递给apply函数。


2
正是我所需要的。值得注意的是,这不需要创建一个专门处理Series(或df)的自定义函数。完美! - Connor
2
唯一剩下的问题是:如何将关键字参数传递给 add(i1)中的第一个参数,并使用 i2 进行迭代? - Connor
1
我认为这是最好的答案。 - crypdick
同意@Connor的评论,当第一个参数必须指定时,如何处理2个位置参数? - timmey
这似乎是最明确、最符合Python风格的方式。 - undefined

53
Series.apply(func, convert_dtype=True, args=(), **kwds)

args : tuple

x = my_series.apply(my_function, args = (arg1,))

12
谢谢!你能解释一下为什么在args = (arg1,)中第一个参数后面需要一个逗号吗? - DrMisha
25
@MishaTeplitskiy,你需要逗号,这样Python才能理解括号内的内容是一个长度为1的元组。 - prooffreader
5
要为func添加参数,如果我想应用pd.Series.mean(axis=1),如何添加axis=1呢? - Little Bobby Tables
1
顺便提一下,您也可以添加一个关键字参数而不使用<args>参数(例如:x = my_series.apply(my_function, keyword_arg=arg1),其中<keyword_arg>是my_function的输入参数之一) - lev
1
此回复过于简短,没有解释任何内容。 - FistOfFury
显示剩余5条评论

41
您可以通过未命名参数(作为元组传递给args参数)或通过其他关键字参数(由kwds参数内部捕获为字典)将任意数量的参数传递给apply调用的函数。
例如,让我们构建一个函数,对于介于3和6之间的值返回True,否则返回False。
s = pd.Series(np.random.randint(0,10, 10))
s

0    5
1    3
2    1
3    1
4    6
5    0
6    3
7    4
8    9
9    6
dtype: int64

s.apply(lambda x: x >= 3 and x <= 6)

0     True
1     True
2    False
3    False
4     True
5    False
6     True
7     True
8    False
9     True
dtype: bool

这个匿名函数不是很灵活。让我们创建一个普通函数,有两个参数来控制我们想要在序列中的最小值和最大值。

def between(x, low, high):
    return x >= low and x =< high

我们可以通过向 args 传递未命名的参数来复制第一个函数的输出:

s.apply(between, args=(3,6))

或者我们可以使用命名参数

s.apply(between, low=3, high=6)

甚至可以两者结合起来

s.apply(between, args=(3,), high=6)

这很清楚!谢谢 - sguo

3
#sample dataframe

import pandas as pd

df1=pd.DataFrame({'a':[3,4,7],'b':[4,2,2]})

#my function

def add_some(p,q,r):return p+q+r

df2=df1[["a","b"]].apply(add_some, args=(3,2))

print(df2)

_ a b

0 8 9

1 9 7

2 12 7


2

你只需要在参数后面加上逗号,就可以在整个列表上运行函数。下面给出了一个示例。同样的过程也可以在集合上完成。

df = {"name" : [2,3,4,6],
      
      "age" : [4,10, 30, 20]
      }

print("Before")
df = pd.DataFrame(df)

print(df)

def fun(a, b):
    for c in b:
        a +=c
    return a
[![enter image description here][1]][1]

listt = set([3,4,5])

print("After")
new = df.apply(fun, args = (listt,))
print(new)

Result


1
大部分的问题已经在其他答案中得到了解决,我想重复一件你可能错过的事情,那就是在参数元组中的参数后面加上逗号,请参考下面的示例:
df['some_column'].apply(function_name, args=(arg1 ,) #Here comma is necessary.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接