使用np.where实现多条件列赋值且不覆盖数据,解决嵌套括号过多问题
解决方案
针对190+层条件判断的场景,以下两种方案可完全替代嵌套np.where,同时避免层数限制和数据覆盖问题:
方案1:使用np.select直接替换多层嵌套(最适配现有逻辑)
np.select不需要嵌套结构,仅需把所有判断条件、对应返回值分别整理为两个同顺序的列表即可,会按传入的条件顺序优先匹配第一个满足的规则,不会出现数据覆盖问题。
代码示例:
import pandas as pd import numpy as np # 第一步:按原逻辑的优先级顺序整理所有判断条件到列表 conditions = [ (d['X'] < xo) & (d['Y'] < yo), (d['X'] < xo) & (d['Y'] > yo) & (d['Y'] < yo*2), (d['X'] < xo) & (d['Y'] > yo*2) & (d['Y'] < yo*3), # 剩余所有条件按优先级顺序补充即可,无需嵌套 ] # 第二步:按条件的对应顺序,整理返回值到列表 choices = [ dfc1.loc[0].values[0], dfc1.loc[1].values[0], dfc1.loc[2].values[0], # 对应条件顺序补充所有返回值 ] # 第三步:直接生成新列,default参数填写所有条件都不满足时的默认值 d['Start'] = np.select(conditions, choices, default=np.nan)
如果不想手写190+条条件和返回值,可以根据X、Y的区间划分规则循环生成两个列表,实现效率更高。
方案2:分箱+查找表(性能最优,适合固定区间映射逻辑)
你的判断逻辑本质是把X、Y按固定步长(xo、yo)分箱后映射对应值,完全可以先生成分箱编号,再用预构建的查找表直接取值,不需要写任何判断条件:
# 第一步:把所有dfc整合成二维查找矩阵,行对应Y的分箱序号,列对应X的分箱序号 lookup_mat = pd.concat([dfc1, dfc2, dfc3, dfc4, dfc5], axis=1).values # 第二步:给X、Y生成分箱序号,right=False表示区间左闭右开,和原判断逻辑一致 x_bins = [i * xo for i in range(0, 6)] # 按X的最大区间数调整边界 y_bins = [i * yo for i in range(0, 13)] # 按Y的最大区间数调整边界 d['x_bin'] = pd.cut(d['X'], bins=x_bins, labels=False, right=False) d['y_bin'] = pd.cut(d['Y'], bins=y_bins, labels=False, right=False) # 第三步:直接索引取值生成新列 d['Start'] = lookup_mat[d['y_bin'], d['x_bin']]
拆分np.where语句的修正方案
如果坚持拆分为多条语句执行,原来的覆盖问题是因为每次赋值都针对全表,只需增加未赋值判断即可避免覆盖:
# 先初始化新列为空值 d['Start'] = np.nan # 每次赋值仅针对满足条件且还未赋值的行 d.loc[(d['X'] < xo) & (d['Y'] < yo) & d['Start'].isna(), 'Start'] = dfc1.loc[0].values d.loc[(d['X'] < xo) & (d['Y'] > yo) & (d['Y'] < yo*2) & d['Start'].isna(), 'Start'] = dfc1.loc[1].values # 后续规则按同样逻辑补充即可
内容的提问来源于stack exchange,提问作者JayRSP
相关产品推荐
相关产品推荐

