ValueError:DataFrame真值不明确问题及apply函数用法咨询
首先来看你遇到的问题:你想给DataFrame新增一列计算total和downloaded的百分比差值,但只在downloaded不为0时计算,否则设为0。你写的函数运行后抛出了ValueError,我们先来拆解这个错误。
错误原因解释
你写的diff函数接收的是整个DataFrame对象,而代码里的if ratings[ratings.downloaded > 0]:这一行,是在判断一个布尔索引后的DataFrame的真假——但Pandas里,一个包含多个元素的DataFrame/Series没法直接用if判断真假,因为它不知道你是要判断所有元素为真、还是至少一个为真,所以就会抛出这个“truth value ambiguous”的错误,提示你用.empty、.any()、.all()这类方法,但这其实不是你要的逻辑,因为你的目标是逐行判断,而不是判断整个DataFrame的状态。
场景是否适合用apply函数?
完全适合!apply函数就是用来对DataFrame的行或列执行自定义逻辑的工具,而且可以轻松加入条件判断——只要你让apply逐行处理,而不是把整个DataFrame丢给函数。
具体实现方式
方式1:使用apply逐行处理
修改你的函数,让它接收每一行的Series对象,而不是整个DataFrame,然后指定axis=1让apply逐行执行:
import pandas as pd # 你的原始DataFrame ratings = pd.DataFrame({ 'total': [2, 12, 1, 1, 0], 'downloaded': [2, 12, 1, 1, 0], 'avg_rating': [5.0, 4.5, 5.0, 4.0, 0.0], 'id': [1, 2, 3, 4, 5] }) def diff(row): # 现在row是单一行的Series,判断单个数值不会有歧义 if row['downloaded'] > 0: return (row['total'] - row['downloaded']) / row['downloaded'] else: return 0 # axis=1表示逐行应用函数 ratings['Pct Diff'] = ratings.apply(diff, axis=1)
运行后你会得到正确的结果:
total downloaded avg_rating id Pct Diff 0 2 2 5.0 1 0.0 1 12 12 4.5 2 0.0 2 1 1 5.0 3 0.0 3 1 1 4.0 4 0.0 4 0 0 0.0 5 0.0
方式2:更高效的向量化操作(推荐)
如果你的数据量很大,apply的效率会不如Pandas的向量化操作。我们可以直接用where方法或者numpy的np.where来实现,不需要循环/逐行处理:
# 方法一:用Pandas的where方法 ratings['Pct Diff'] = ((ratings['total'] - ratings['downloaded']) / ratings['downloaded']).where(ratings['downloaded'] > 0, 0) # 方法二:用numpy的where import numpy as np ratings['Pct Diff'] = np.where( ratings['downloaded'] > 0, (ratings['total'] - ratings['downloaded']) / ratings['downloaded'], 0 )
这种方式是对整个列进行批量运算,速度比apply快很多,而且代码更简洁。
内容的提问来源于stack exchange,提问作者Ken Wallace

