python pandas:将数据帧传递给df.apply

jbo*_*xxx 6 python dataframe pandas

本网站的长期用户,但第一次提问!感谢多年来一直在回答问题的所有仁慈的用户:)

df.apply最近一直在使用,理想情况下希望将数据帧传递到args参数中,看起来像这样: df.apply(testFunc, args=(dfOther), axis = 1)

我的最终目标是遍历我传入args参数的数据帧 df ,并针对原始数据帧的每一行检查逻辑,例如,并从 dfOther . 所以说我有一个这样的功能:

def testFunc(row, dfOther):
    for index, rowOther in dfOther.iterrows():
        if row['A'] == rowOther[0] and row['B'] == rowOther[1]:
            return dfOther.at[index, 'C']

df['OTHER'] = df.apply(testFunc, args=(dfOther), axis = 1)
Run Code Online (Sandbox Code Playgroud)

我目前的理解是args需要一个 Series 对象,因此如果我实际运行它,我们会收到以下错误:

ValueError: The truth value of a DataFrame is ambiguous. 
Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)

然而,在我写testFunc它只传递一个数据帧之前,我实际上已经写了priorTestFunc,它看起来像这样......而且它有效!

def priorTestFunc(row, dfOne, dfTwo):
    for index, rowOne in dfOne.iterrows():
        if row['A'] == rowOne[0] and row['B'] == rowOne[1]:
            return dfTwo.at[index, 'C']

df['OTHER'] = df.apply(testFunc, args=(dfOne, dfTwo), axis = 1)
Run Code Online (Sandbox Code Playgroud)

所以令我沮丧的是,我已经养成了这样写的习惯,testFunc而且它一直在按预期工作:

def testFunc(row, dfOther, _):
    for index, rowOther in dfOther.iterrows():
        if row['A'] == rowOther[0] and row['B'] == rowOther[1]:
            return dfOther.at[index, 'C']

df['OTHER'] = df.apply(testFunc, args=(dfOther, _), axis = 1)
Run Code Online (Sandbox Code Playgroud)

如果有人能让我知道为什么会这样,也许我会容易出现错误,或者可能是解决此类问题的另一种选择,我将不胜感激!

编辑:根据评论的要求:我的 dfs 通常如下所示.. 他们将有两个匹配的列,并将返回dfOther.at[index, column]我考虑过的值,pd.concat([dfOther, df])但是我将运行算法测试条件df,然后相应地从上的特定值dfOther(也将更新),我希望 df相对整洁,而不是制作多索引并在其中抛出几乎所有内容。我也知道df.iterrows一般来说速度很慢,但是这些数据帧最多大约有 500 行,因此目前对我来说可扩展性并不是真正的大问题。

df
Out[10]: 
    A    B      C
0  foo  bur   6000
1  foo  bur   7000
2  foo  bur   8000
3  bar  kek   9000
4  bar  kek  10000
5  bar  kek  11000

dfOther
Out[12]: 
    A    B      C
0  foo  bur   1000
1  foo  bur   2000
2  foo  bur   3000
3  bar  kek   4000
4  bar  kek   5000
5  bar  kek   6000
Run Code Online (Sandbox Code Playgroud)

ayh*_*han 7

错误在这一行:

  File "C:\Anaconda3\envs\p2\lib\site-packages\pandas\core\frame.py", line 4017, in apply
    if kwds or args and not isinstance(func, np.ufunc):
Run Code Online (Sandbox Code Playgroud)

这里,if kwds or args就是检查args传递给的长度是否apply大于0。检查一个iterable是否为空是一种常用的方法:

l = []

if l:
    print("l is not empty!")
else:
    print("l is empty!")
Run Code Online (Sandbox Code Playgroud)

l is empty!

l = [1]

if l:
    print("l is not empty!")
else:
    print("l is empty!")
Run Code Online (Sandbox Code Playgroud)

l is not empty!

如果您将元组传递给df.applyas args,它将返回 True 并且不会有问题。但是,Python 不会将 (df) 解释为元组:

type((df))
Out[39]: pandas.core.frame.DataFrame
Run Code Online (Sandbox Code Playgroud)

它只是括号内的一个 DataFrame/变量。当你输入if df

if df:
    print("df is not empty")

Traceback (most recent call last):

  File "<ipython-input-40-c86da5a5f1ee>", line 1, in <module>
    if df:

  File "C:\Anaconda3\envs\p2\lib\site-packages\pandas\core\generic.py", line 887, in __nonzero__
    .format(self.__class__.__name__))

ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)

您会收到相同的错误消息。但是,如果您使用逗号来表示它是元组,则它可以正常工作:

if (df, ):
    print("tuple is not empty")

tuple is not empty
Run Code Online (Sandbox Code Playgroud)

因此,args=(dfOther)通过使其成为单例来添加逗号 应该可以解决问题。

df['OTHER'] = df.apply(testFunc, args=(dfOther, ), axis = 1)
Run Code Online (Sandbox Code Playgroud)