为什么pandas的apply会计算两次

39

我正在使用Pandas DataFrame对象的apply方法。当我的DataFrame只有一列时,似乎应用的函数被调用了两次。问题是为什么?我能停止这种行为吗?

代码:

import pandas as pd

def mul2(x):
    print ('hello')
    return 2*x

df = pd.DataFrame({'a': [1,2,0.67,1.34]})
df.apply(mul2)

输出:

hello
hello

0  2.00
1  4.00
2  1.34
3  2.68

我从函数中打印出'hello'。因为打印了两次,所以我知道它被应用了两次。如果我有两列,'hello' 就会打印三次。更有甚者,当我只调用应用到列时,'hello' 打印了四次。

代码:

df.a.apply(mul2)

输出:

hello
hello
hello
hello
0    2.00
1    4.00
2    1.34
3    2.68
Name: a, dtype: float64
3个回答

16

这种行为是有意为之的,作为一种优化措施。

详见文档

在当前实现中,apply 在第一列/行上调用 func 两次以决定它能否采用快速或慢速的代码路径。 如果 func 具有副作用,则可能导致意外行为,因为它们将对第一列/行产生两倍的效果。


2
有没有避免这种情况的方法? - CMCDragonkai
我不知道,也不认为是这样。仅仅因为它被视为一种优化。 - MERose
3
显然,版本号不低于0.25.0已经解决了这个问题。 - CMCDragonkai
= 0.25.0版本的Pandas库中,groupby组合器不再需要执行两次apply函数:https://github.com/pandas-dev/pandas/pull/24748#issuecomment-532148732 但是普通的apply函数仍然需要执行两次。
- CMCDragonkai
@CMCDragonkai 从1.1版本开始,df.apply的行为也已经得到了修正,更多信息请参见此处 - cs95

13
可能与这个问题有关。使用groupby时,应用的函数会多调用一次,以查看是否可以进行某些优化。我猜测在这里发生了类似的情况。目前看起来没有任何办法可以避免它(尽管我对你所看到的行为的来源可能是错误的)。你需要它不做那个额外的调用吗?
此外,在对该列应用时调用四次是正常的。当你获取一列时,你得到一个Series而不是DataFrame。apply在Series上将函数应用于每个元素。由于您的列中有四个元素,因此函数被调用了四次。

我正在使用的函数是递归的。我试图避免它进行不必要的递归计算。现在还没有问题,但以后可能会有。 - piRSquared

10

这个问题已经在pandas 1.1版本中修复,请升级!

现在,DataFrame上的applyapplymap只会计算第一行/列一次

最初,我们在GroupBy.applySeries/df.apply中评估了第一组两次。第一组被评估两次的原因是因为apply想知道它是否可以“优化”计算(如果apply接收到一个numpy或cythonized函数,则有时可以实现这种优化)。在pandas 0.25中,这个问题已被修复,现在,在pandas 1.1中,此问题也将被修复。


旧行为 [pandas <= 1.0.X]

pd.__version__ 
# '1.0.4'

df.apply(mul2)
hello
hello

      a
0  2.00
1  4.00
2  1.34
3  2.68

新行为 [pandas >= 1.1]

pd.__version__
# '1.1.0.dev0+2004.g8d10bfb6f'

df.apply(mul2)
hello

      a
0  2.00
1  4.00
2  1.34
3  2.68

1
看看那个声望分数...恭喜你获得了20万!很高兴见到你。 - piRSquared
@piRSquared 先生,好久不见了!希望能在聊天中抓住你的身影,但是你已经无法被ping到了:( - cs95
@cs95,我遇到了一个问题,即使在1.1.0中也没有解决。https://stackoverflow.com/questions/63400773/pandas-1-1-0-misses-second-row-in-df-apply - Lucas Aimaretto
看看Lucas的帖子。这是一个在apply中会原地更新行的bug。 - Trenton McKinney
我使用的是1.4.4版本,而且groupby.apply对于每个分组都会调用函数两次! - undefined
显示剩余2条评论

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