为啥我的 Pandas 引用多个列的“应用”函数不起作用? [关闭]

Posted

技术标签:

【中文标题】为啥我的 Pandas 引用多个列的“应用”函数不起作用? [关闭]【英文标题】:Why isn't my Pandas 'apply' function referencing multiple columns working? [closed]为什么我的 Pandas 引用多个列的“应用”函数不起作用? [关闭] 【发布时间】:2013-04-27 13:13:46 【问题描述】:

当使用具有以下数据框的多列时,我的 Pandas 应用功能存在一些问题

df = DataFrame ('a' : np.random.randn(6),
                 'b' : ['foo', 'bar'] * 3,
                 'c' : np.random.randn(6))

还有下面的函数

def my_test(a, b):
    return a % b

当我尝试使用以下功能应用此功能时:

df['Value'] = df.apply(lambda row: my_test(row[a], row[c]), axis=1)

我收到错误消息:

NameError: ("global name 'a' is not defined", u'occurred at index 0')

我不明白这条消息,我正确定义了名称。

非常感谢您在此问题上的任何帮助

更新

感谢您的帮助。我确实在代码中犯了一些语法错误,索引应该放在''。但是我仍然使用更复杂的功能遇到同样的问题,例如:

def my_test(a):
    cum_diff = 0
    for ix in df.index():
        cum_diff = cum_diff + (a - df['a'][ix])
    return cum_diff 

【问题讨论】:

尽量避免使用apply。如果您不确定是否需要使用它,则可能不需要。我建议看看When should I ever want to use pandas apply() in my code?。 这只是关于引用数据框列的语法错误,以及为什么函数需要参数。至于你的第二个问题,函数my_test(a) 不知道df 是什么,因为它没有作为参数传入(除非df 应该是一个全局的,这将是一个糟糕的做法)。您需要将函数内部所需的所有值作为参数传递(最好按顺序),否则函数如何知道df 的来源?此外,在一个充斥着全局变量的命名空间中进行编程是一种不好的做法,你不会捕捉到这样的错误。 【参考方案1】:

我已经给出了上面讨论的所有三个的比较。

使用价值观

%timeit df['value'] = df['a'].values % df['c'].values

每个循环 139 µs ± 1.91 µs(7 次运行的平均值 ± 标准偏差,每次 10000 个循环)

没有价值观

%timeit df['value'] = df['a']%df['c'] 

每个循环 216 µs ± 1.86 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)

应用功能

%timeit df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)

每个循环 474 µs ± 5.07 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)

【讨论】:

【参考方案2】:

这与之前的解决方案相同,但我在 df.apply 本身中定义了函数:

df['Value'] = df.apply(lambda row: row['a']%row['c'], axis=1)

【讨论】:

【参考方案3】:

以上所有建议都有效,但如果您希望计算效率更高,您应该利用 numpy 向量操作(as pointed out here)。

import pandas as pd
import numpy as np


df = pd.DataFrame ('a' : np.random.randn(6),
             'b' : ['foo', 'bar'] * 3,
             'c' : np.random.randn(6))

示例 1:循环使用 pandas.apply():

%%timeit
def my_test2(row):
    return row['a'] % row['c']

df['Value'] = df.apply(my_test2, axis=1)

最慢的运行时间是最快的运行时间的 7.49 倍。这可以 表示正在缓存中间结果。 1000 个循环,最好的 3:每个循环 481 µs

示例 2:使用 pandas.apply() 进行矢量化:

%%timeit
df['a'] % df['c']

最慢的运行时间是最快的运行时间的 458.85 倍。这可以 表示正在缓存中间结果。 10000 个循环,最好的 3:每个循环 70.9 µs

示例 3:使用 numpy 数组进行矢量化:

%%timeit
df['a'].values % df['c'].values

最慢的运行时间是最快的运行时间的 7.98 倍。这可以 表示正在缓存中间结果。 100000 次循环,最佳 3:每个循环 6.39 µs

因此使用 numpy 数组进行矢量化将速度提高了近两个数量级。

【讨论】:

对于大数字,结果变化更大,例如用 10K 替换 6,我分别得到 248 ms、332 µs、263 µs。所以两个矢量化解决方案彼此更接近,但非矢量化解决方案慢了 1000 倍。 (在 python-3.7 上测试)【参考方案4】:

假设我们要将函数 add5 应用于 DataFrame df 的“a”和“b”列

def add5(x):
    return x+5

df[['a', 'b']].apply(add5)

【讨论】:

在尝试您的代码 sn-p 时出现以下错误。 TypeError: ('must be str, not int', 'occured at index b') 你能看看吗? 你的dataframe的b列是字符串类型或者对象类型的列,应该是整数列加上数字。 更改不是只在分配后应用吗?【参考方案5】:

您似乎忘记了字符串的''

In [43]: df['Value'] = df.apply(lambda row: my_test(row['a'], row['c']), axis=1)

In [44]: df
Out[44]:
                    a    b         c     Value
          0 -1.674308  foo  0.343801  0.044698
          1 -2.163236  bar -2.046438 -0.116798
          2 -0.199115  foo -0.458050 -0.199115
          3  0.918646  bar -0.007185 -0.001006
          4  1.336830  foo  0.534292  0.268245
          5  0.976844  bar -0.773630 -0.570417

顺便说一句,在我看来,以下方式更优雅:

In [53]: def my_test2(row):
....:     return row['a'] % row['c']
....:     

In [54]: df['Value'] = df.apply(my_test2, axis=1)

【讨论】:

谢谢,你说得对,我忘记了''。但是,对于更复杂的功能,我仍然有同样的问题。我非常感谢您的帮助。谢谢 @Andy 关注 [53-54] 允许您应用更复杂的功能。 @Andy 你可以像 In[53] 方式定义你的复杂函数。 所有应用策略的表现都一样吗?我是 pandas 的新手,总是觉得 apply 有点神秘,但你在 [53-54] 中的策略对我来说很容易理解(并希望记住)......在一张大桌子上它是否和其他形式的 apply 一样快介绍? axis=1 在这里很重要【参考方案6】:

如果只想计算(a列)%(b列),则不需要apply,直接做即可:

In [7]: df['a'] % df['c']                                                                                                                                                        
Out[7]: 
0   -1.132022                                                                                                                                                                    
1   -0.939493                                                                                                                                                                    
2    0.201931                                                                                                                                                                    
3    0.511374                                                                                                                                                                    
4   -0.694647                                                                                                                                                                    
5   -0.023486                                                                                                                                                                    
Name: a

【讨论】:

我知道,这只是一个例子来说明我在将函数应用于多列时遇到的问题

以上是关于为啥我的 Pandas 引用多个列的“应用”函数不起作用? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

pandas编写自定义函数计算多个数据列的加和(sum)使用groupby函数和apply函数聚合计算分组内多个数据列的加和

pandas使用stack函数map函数unstack函数以及字典同时替换dataframe多个数据列的内容

Pandas 应用返回两个新列的函数

为啥我的应用程序不能以 pandas_udf 和 PySpark+Flask 开头?

将函数应用于 Pandas.DataFrame 中两列的每个组合的更好方法

pandas使用unique函数计算dataframe单个数据列中的独特值或者计算dataframe多个数据列的独特值(get unique values of column or columns)