Pandas DataFrame.apply()运行不符合预期的原因及正确写法
pandas按条件修改列值异常问题排查与实现
问题根因
- 你最初的
apply写法存在核心逻辑错误:对sqft_living单列执行apply时,传入的函数会逐元素触发一次,你的数据集共21613行,函数就会被调用2万余次。但你在函数内部没有操作当前传入的单个元素,而是直接对整个grade列执行全量加值,相当于每遍历一行数据,就给所有行的grade统一加1或加2。 - 异常数值的计算逻辑完全可追溯:数据集中超过99%的房源
sqft_living大于400,每遍历到这类房源就给全列grade加2,累计遍历完成后全列grade累计加值超过4万,叠加原始grade的6-13的基础值,刚好得到你看到的8万量级结果,末尾数字和原始值一致就是累计加值没有改变个位数值的缘故。 - 你修改为赋值
+/-后得到全列-的结果并非逻辑正确,只是覆盖式赋值的巧合:最后一次函数调用时传入的sqft_living值大于400,直接将全列grade覆盖为-,前面所有次的赋值结果都被最后一次操作覆盖,才得到了统一的输出。
正确实现方式
方式1:严格使用DataFrame.apply()实现
注意apply需要作用在整个DataFrame上,指定axis=1按行遍历,函数接收单行数据作为参数,返回当前行修改后的grade值,禁止在函数内部直接操作全表:
def grade_adjust(row): sqft = row['sqft_living'] if 0 < sqft < 400: return row['grade'] + 1 elif sqft > 400: return row['grade'] + 2 # sqft等于0或400的边界场景可根据业务需求调整返回值 return row['grade'] housing['grade'] = housing.apply(grade_adjust, axis=1)
方式2:pandas向量化实现(推荐,性能远高于apply)
逐行apply本质是Python层循环,数据量大时性能很差,优先使用pandas原生的条件选择赋值,执行效率是apply的数十倍:
# 筛选sqft_living大于400的行,grade统一加2 gt400_mask = housing['sqft_living'] > 400 housing.loc[gt400_mask, 'grade'] += 2 # 筛选sqft_living在0-400区间的行,grade统一加1 lt400_mask = (housing['sqft_living'] > 0) & (housing['sqft_living'] < 400) housing.loc[lt400_mask, 'grade'] += 1
也可以用numpy.where实现嵌套条件赋值,代码更简洁:
import numpy as np housing['grade'] = np.where( (housing['sqft_living'] > 0) & (housing['sqft_living'] < 400), housing['grade'] + 1, np.where( housing['sqft_living'] > 400, housing['grade'] + 2, housing['grade'] ) )
注意:原逻辑没有处理
sqft_living等于400或等于0的边界场景,实际使用时需要根据业务规则补充对应逻辑。
内容的提问来源于stack exchange,提问作者Gautam
相关产品推荐
相关产品推荐

