How to Re-Write Lambda Function (via Pandas .apply() method) to Beat Famous "ValueError: The truth value of a Series is ambiguous."?

How to Re-Write Lambda Function (via Pandas .apply() method) to Beat Famous "ValueError: The truth value of a Series is ambiguous."?

编辑:this notebook 中发布的解决方案。特别感谢 Étienne Célèry 和 ifly6!


我正在想办法克服可怕的错误:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

d = {
    'nickname': ['bobg89', 'coolkid34','livelaughlove38'], 
    'state': ['NY', 'CA','TN'],
    'score': [100, 200,300]
}
df = pd.DataFrame(data=d)
df_2 = df.copy() #for use in the second non-lambda part
print(df)

这输出:

          nickname state  score
0           bobg89    NY    100
1        coolkid34    CA    200
2  livelaughlove38    TN    300

那么如果他们来自纽约,目标是将分数加 50。

def add_some_love(state_value,score_value,name):
     if state_value == name:
          return score_value + 50
     else:
          return score_value

然后我们可以使用 lambda 函数应用该函数。

df['love_added'] = df.apply(lambda x: add_some_love(x.state, x.score, 'NY'), axis=1)
print(df)

这让我们:

          nickname state  score  love_added
0           bobg89    NY    100         150
1        coolkid34    CA    200         200
2  livelaughlove38    TN    300         300

这是我在没有 lambda 的情况下尝试编写它的地方,这就是我遇到错误的地方。

@MSeifert 的 似乎解释了为什么会发生这种情况(该函数正在查看整列而不是列中的一行,但我还认为将 axis = 1 传递给 .apply() 方法将按行应用函数,并解决问题)。

然后我这样做:

df2['love_added'] = df2.apply(add_some_love(df2.state, df2.score, 'NY'), axis=1)
print(df2)

然后你得到错误:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

所以我尝试了这些解决方案,但我似乎无法弄清楚如何重写 add_some_love() 函数,以便在没有 lambda 函数的情况下它可以 运行 正确。

有人有什么建议吗?

非常感谢您的时间和考虑。

您可以改为使用 np.where:

df['score'] = np.where(df['state'] == 'NY', df['score'] + 50, df['score'])

这将产生与您应用的函数相同的结果,同时性能更高。


lambda 函数的 non-use 存在的问题是您实际上并未将行传递给您的函数。您实际传递的是整个列 df['score'],因为这是您告诉计算机要做的。

你的函数中发生的事情是计算机询问:

# if state_value == name ...
if df['score'] == 'NY':
    ...

这自然会引发您的错误,因为 df['score'] == 'NY' 是一系列布尔变量,而不是 单个 布尔变量,这是 if 所需要的声明。

您的 add_some_love 函数需要字符串输入才能执行比较 if state_value == name。当您在 DataFrame 上应用 lambda 函数时,您可以将 每个单元格 传递给该函数,而不是整个系列。 如果没有 lambda 函数,您将无法使用那个确切的 add_some_love 函数。

如果你还想使用apply(),试试这个功能:

def add_some_love(row, name):
   if row.state == name:
       row.score = row.score + 50
   return row

df_2 = df_2.apply(add_some_love, axis=1, args=('NY',))

但是,这应该是最快最有效的:

FILTER = df_2['state'] == 'NY'
df_2.loc[FILTER, 'score'] = df_2.loc[FILTER, 'score'] + 50