pandas根据另一列阈值分类赋值时结果异常问题排查
问题场景
我的数据形式如下:
我编写了如下脚本,用于为RP8_Recruise列赋值:规则为NEAR_DIST小于等于100米时赋值为"Y",同时给RP_8RecrType列赋值为"PD";NEAR_DIST大于100米时RP8_Recruise赋值为"N",RP_8RecrType设为空值。
nrows = plots_dist_joined.shape[0] for i in range(0, nrows): # 距离干扰采伐区在目标范围内的样地 if (plots_dist_joined.iloc[i,9] < 100) | (plots_dist_joined.iloc[i,9] == 100): plots_dist_joined["RP_"+reporting_period+"Recruise"] = "Y" plots_dist_joined["RP_"+reporting_period+"RecrType"] = "PD" # 距离干扰采伐区不在目标范围内的样地 else: plots_dist_joined["RP_"+reporting_period+"Recruise"] = "N" plots_dist_joined["RP_"+reporting_period+"RecrType"] = np.nan
运行代码后RP_8Recruise列所有值都被填充为"N",但数据中实际存在NEAR_DIST小于100米的记录(对应ID为59197、40、84、92、132),无法定位问题。
问题根因
代码逻辑错误出在赋值粒度上:
- 循环内每次写
plots_dist_joined[列名] = 值的操作,是对整列所有行统一赋值,不是只修改当前遍历到的第i行 - 循环逐行执行时,前面对符合条件行设置的"Y",会被后续行的判断结果覆盖。如果最后一行的NEAR_DIST大于100,整列就会被最终覆盖为"N",之前所有的"Y"赋值都会被冲掉
- 额外风险:用硬编码索引
iloc[i,9]取NEAR_DIST列,一旦列顺序变动就会取错字段,导致判断完全失效
修复方案
pandas做这类条件赋值优先用向量化操作,不需要写逐行循环,运行速度更快也不会出现整列覆盖的问题:
import numpy as np import pandas as pd # 提前定义列名,避免重复拼接字符串 # 建议直接写NEAR_DIST的实际列名替代硬编码索引,减少出错概率,比如dist_col = "NEAR_DIST" dist_col = plots_dist_joined.columns[9] recruise_col = f"RP_{reporting_period}Recruise" recrtype_col = f"RP_{reporting_period}RecrType" # 构造判断条件:距离<=100米 within_dist_mask = plots_dist_joined[dist_col] <= 100 # 分条件赋值 plots_dist_joined.loc[within_dist_mask, recruise_col] = "Y" plots_dist_joined.loc[within_dist_mask, recrtype_col] = "PD" plots_dist_joined.loc[~within_dist_mask, recruise_col] = "N" plots_dist_joined.loc[~within_dist_mask, recrtype_col] = np.nan
如果一定要保留逐行循环写法(数据量大于1万行时速度会比向量化写法慢几十到上百倍,不推荐),需要把赋值目标指定为当前行:
nrows = plots_dist_joined.shape[0] recruise_col = f"RP_{reporting_period}Recruise" recrtype_col = f"RP_{reporting_period}RecrType" # 提前获取列索引,避免循环内重复计算 recruise_col_idx = plots_dist_joined.columns.get_loc(recruise_col) recrtype_col_idx = plots_dist_joined.columns.get_loc(recrtype_col) for i in range(nrows): dist_val = plots_dist_joined.iloc[i, 9] if dist_val <= 100: plots_dist_joined.iloc[i, recruise_col_idx] = "Y" plots_dist_joined.iloc[i, recrtype_col_idx] = "PD" else: plots_dist_joined.iloc[i, recruise_col_idx] = "N" plots_dist_joined.iloc[i, recrtype_col_idx] = np.nan
结果校验
赋值完成后可以通过两个方式核对结果:
- 统计符合距离条件的行数和赋值为"Y"的行数,二者相等则逻辑正确
# 距离<=100的行数 print(plots_dist_joined[plots_dist_joined.iloc[:,9] <= 100].shape[0]) # Recruise列为Y的行数 print(plots_dist_joined[plots_dist_joined[recruise_col] == "Y"].shape[0])
- 单独筛选提到的几个ID的记录,检查对应列的赋值是否符合预期。
内容的提问来源于stack exchange,提问作者Gloria Desanker
相关产品推荐
相关产品推荐

