最常用的是 np.where(支持多层嵌套),比 pd.Series.apply 快一个数量级;须用 &、|、~ 替代 and/or/not,注意括号;三层以上逻辑建议拆中间变量或改用 pd.cut/map;eval 可提升可读性,支持 @ 引用外部变量;统计汇总优先用 crosstab 或 groupby 而非新增列。

用 np.where 或 pd.Series.mask 处理多列组合条件判断
直接在 df['new_col'] = ... 中写嵌套 if-else 会报错或返回标量,必须用向量化函数。最常用的是 np.where(支持多层嵌套),比 pd.Series.apply 快一个数量级。
常见错误:把 Python 的 and/or 直接用于 Series 比较,触发 ValueError: The truth value of a Series is ambiguous。
- 用
&、|、~替代and、or、not(注意括号!比如(df.a > 1) & (df.b == 'x')) - 三层以上逻辑建议拆成中间变量,避免括号嵌套出错
-
np.where(cond, val_if_true, np.where(...))可实现 if-elif-else;但超过 4 层推荐改用pd.cut或pd.Series.map+ 字典
import numpy as np
df['risk_level'] = np.where(
(df['age'] < 18), 'minor',
np.where((df['income'] > 100000) & (df['debt_ratio'] < 0.3), 'low', 'high')
)用 pd.DataFrame.eval 简化长表达式逻辑
当条件涉及 3+ 列、含算术运算(如 revenue - cost > margin_target)时,eval 能显著减少代码长度和括号错误。
注意:eval 默认不支持 isnull 这类方法调用,需用 pd.isna() 形式,且不能调用自定义函数。
立即学习“Python免费学习笔记(深入)”;
- 字符串中列名直接写,不用加
df.前缀 - 支持
@var引用外部变量(比如阈值@threshold) - 性能略低于纯 NumPy 运算,但可读性提升明显,适合中等复杂度逻辑
threshold = 5000
df['is_profitable'] = df.eval('revenue - cost > @threshold and status != "draft"')用 pd.crosstab 或 groupby().agg 实现跨列条件计数/聚合
不是所有“统计”都要先加新列——如果最终只要汇总结果(如“高收入且低负债的用户数”),直接用分组聚合更高效,内存占用小,且天然支持多维交叉。
容易忽略的点:crosstab 默认只统计频次,若要均值、最大值等,得切到 groupby;而 groupby 的布尔条件必须提前转为分类列或用 query 预过滤。
-
pd.crosstab(df['region'], df['income'].gt(80000) & df['debt_ratio'].lt(0.2))返回二维频次表 df.query('income > 80000 and debt_ratio 更灵活但会丢弃不满足条件的行- 想保留全量分组结构(包括 0 计数),用
groupby(..., observed=False)或crosstab(..., dropna=False)
警惕 NaN 在跨列逻辑中的传播与隐式转换
这是最容易导致结果静默错误的地方:NaN == NaN 返回 False,NaN & True 是 NaN,np.where 遇到 NaN 条件会保留原值或填 None,取决于上下文。
不显式处理 NaN,统计结果可能少几万条却毫无报错提示。
- 用
pd.isna()或df.col.isna()显式判断缺失,别依赖== np.nan - 在
np.where的条件中加入& ~df.col.isna()排除干扰 - 对参与逻辑运算的列,提前用
fillna()或dropna()统一策略,尤其注意字符串列的空字符串和NaN并存情况
复杂点往往不在逻辑本身,而在某列里混着 None、' '、np.nan、float('nan') 四种“空”,它们在布尔上下文中表现完全不同。


















