Pandas:基于Wi与Li列生成SET列并处理NaN值问题
解决DataFrame生成SET列并正确处理NaN值的问题
你遇到的NaN处理问题其实很常见,用循环逐行处理不仅效率低,还容易遗漏NaN的判断逻辑。咱们可以用pandas的向量化操作来完美解决这个需求,既简洁又能准确符合你设定的三个规则。
方案1:使用np.where嵌套判断(最直观)
这个方法先判断Wi和Li是否都不为空,再根据大小关系赋值,否则直接返回NaN:
import pandas as pd import numpy as np # 构造你的示例数据 df = pd.DataFrame({ 'W1': [6, np.nan], 'W2': [6, np.nan], 'W3': [3, np.nan], 'W4': [6, 6], 'L1': [7, np.nan], 'L2': [3, np.nan], 'L3': [6, np.nan], 'L4': [7, np.nan] }) # 循环生成SET1到SET4列 for i in range(1, 5): w_col = f"W{i}" l_col = f"L{i}" # 第一层判断:Wi和Li都不为NaN时才进行大小比较 df[f"SET{i}"] = np.where( df[w_col].notna() & df[l_col].notna(), # 第二层判断:Wi>Li返回1.0,否则0.0 np.where(df[w_col] > df[l_col], 1.0, 0.0), # 只要有一个是NaN,就返回NaN np.nan ) # 查看最终的SET列结果 print(df[["SET1", "SET2", "SET3", "SET4"]])
运行这段代码后,输出完全符合你的预期:
SET1 SET2 SET3 SET4 0 0.0 0.0 1.0 0.0 1 NaN NaN NaN 1.0
方案2:用pd.Series.mask简化逻辑
如果你觉得嵌套np.where有点绕,也可以先生成比较结果,再把含NaN的位置替换成NaN:
for i in range(1, 5): w_col = f"W{i}" l_col = f"L{i}" # 先得到Wi>Li的布尔结果,转成float(True→1.0,False→0.0) set_result = (df[w_col] > df[l_col]).astype(float) # 把Wi或Li为NaN的位置替换成NaN df[f"SET{i}"] = set_result.mask(df[w_col].isna() | df[l_col].isna())
这个方法的逻辑是:先处理所有非NaN的比较,再用mask方法将存在NaN的位置覆盖为NaN,同样能达到要求。
为什么你的循环方案处理不好NaN?
当你用普通循环逐行处理时,需要额外判断每个元素是否为NaN,比如if pd.notna(row[w_col]) and pd.notna(row[l_col]),否则直接赋值NaN。但这种逐行循环的方式在DataFrame数据量大的时候会非常慢,而且代码冗余。而上面的向量化操作是批量处理整个列,pandas会自动处理NaN的逻辑,既高效又不易出错。
内容的提问来源于stack exchange,提问作者oli5679
相关产品推荐
相关产品推荐

