loc赋值是最安全的动态新增列方式:必须用df.loc[condition, 'new_col'] = value,条件需为等长布尔series,多分支推荐np.select而非嵌套np.where。

用 loc 赋值是最安全的动态新增列方式
直接对 DataFrame 新增列并用布尔索引赋值时,df[condition]['new_col'] = value 会触发 SettingWithCopyWarning,甚至静默失败——因为可能操作的是视图而非原数据。必须用 loc 显式定位行和列。
实操建议:
- 始终写成
df.loc[condition, 'new_col'] = value,哪怕'new_col'还不存在,Pandas 会自动创建 - 条件必须是与
df等长的布尔 Series,不能是 Python 原生list或np.array(除非明确 broadcast) - 若条件含
NaN,注意pd.isna()才能正确匹配,== np.nan永远返回False
多个条件组合推荐用 numpy.select 而非嵌套 np.where
当新增列逻辑涉及三段以上分支(比如 “A级”“B级”“C级”“其他”),硬套 np.where(cond1, a, np.where(cond2, b, ...)) 可读性差、易出括号错,且性能略低。
实操建议:
- 用
np.select([cond1, cond2, cond3], [val1, val2, val3], default='other'),条件列表与取值列表一一对应 - 所有条件必须互斥,或按顺序被优先匹配;
default必须显式指定,不能省略 - 条件表达式中避免直接写
df.col > 5 and df.col —— 应改用 <code>&(位与),即(df.col > 5) & (df.col
apply + 自定义函数适合复杂逻辑,但别在循环里调用
如果判断逻辑涉及字符串正则、多列联动计算、外部 API 调用等,apply 是合理选择。但常见错误是写成 df.apply(lambda row: func(row), axis=1) 后再逐行赋值,这比向量化慢一个数量级。
实操建议:
- 优先把逻辑封装成纯函数,然后整列传入:
df['new_col'] = my_func(df['col_a'], df['col_b']) - 若必须用
axis=1,确保函数内不重复访问row['x']多次,而是先提取所需字段再处理 - 避免在
apply内部做 I/O 或数据库查询——这种操作无法向量化,应提前批量获取后映射
新增列类型不一致会隐式转为 object,影响后续计算
比如用 loc 先给部分行赋 int,再给另一些行赋 str,整列会变成 object dtype,导致 .sum() 报错、排序异常、内存占用翻倍。
实操建议:
- 新增列前先预设 dtype:
df['new_col'] = pd.Series(dtype='string')(Pandas 1.0+)或df['new_col'] = pd.NA(自动推断 nullable 类型) - 用
pd.Categorical替代字符串枚举值,节省内存且加速 groupby - 新增完立刻检查:
df['new_col'].dtype和df['new_col'].isna().sum(),确认无意外类型降级或缺失值扩散
df.dtypes 和几个 sample condition 的结果,比事后 debug 快得多。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











