大DataFrame批量赋值优化及SettingWithCopyWarning问题解决
问题
处理Parquet格式数据时,使用Python、Pandas、Numpy根据ph_name列的值批量为inv_group和acc_num列赋值(例如ph_name为'EMPLOYEE'时,inv_group设为'MEMORIAL'、acc_num设为12345)。目前通过循环实现功能,但28896行数据耗时6.24秒,担心大数据量下性能不足,同时出现SettingWithCopyWarning警告。有两个疑问:
- 是否存在更高效的优化方法?
- 该警告是否由不良编码习惯导致,还是只需忽略?
当前实现代码:
look1 = 'EMPLOYEE' look2 = 'CHESTER' look3 = "TONY'S" look4 = "VICTOR'S" tgt1 = 'inv_group' tgt2 = 'acc_num' for x in range(len(df['ph_name'])): if df['ph_name'][x] == look1: df[tgt1][x] = 'MEMORIAL' df[tgt2][x] = 12345 elif df['ph_name'][x] == look2: df[tgt1][x] = 'WALMART' df[tgt2][x] = 45678 elif df['ph_name'][x] == look3: df[tgt1][x] = 'TONYS' df[tgt2][x] = 27359 elif df['ph_name'][x] == look4: df[tgt1][x] = 'VICTOR' df[tgt2][x] = 45378
样本数据及目标效果
基础样本
| unit_name | tgt1 | tgt2 |
|---|---|---|
| EMPLOYEE | Nan | Nan |
| EMPLOYEE | Nan | Nan |
| TONY'S | Nan | Nan |
| CHESTER | Nan | Nan |
| VICTOR'S | Nan | Nan |
| EMPLOYEE | Nan | Nan |
目标效果
| unit_name | tgt1 | tgt2 |
|---|---|---|
| EMPLOYEE | MEMORIAL | 12345 |
| EMPLOYEE | MEMORIAL | 12345 |
| TONY'S | TONYS | 27359 |
| CHESTER | WALMART | 45678 |
| VICTOR'S | VICTOR | 45378 |
| EMPLOYEE | MEMORIAL | 12345 |
解答
1. 高效优化方法
循环遍历Pandas DataFrame的性能极差,因为Pandas底层基于向量化实现,逐行操作会完全浪费其优势。推荐使用映射字典+向量化赋值的方式,速度能提升几个数量级:
首先定义映射关系字典,将每个ph_name对应的目标列值关联起来:
import pandas as pd import numpy as np # 定义映射字典:key为ph_name的值,value为对应的(inv_group, acc_num) mapping = { 'EMPLOYEE': ('MEMORIAL', 12345), 'CHESTER': ('WALMART', 45678), "TONY'S": ('TONYS', 27359), "VICTOR'S": ('VICTOR', 45378) } # 方法1:拆分映射后批量赋值(推荐,性能最优) inv_group_map = {k: v[0] for k, v in mapping.items()} acc_num_map = {k: v[1] for k, v in mapping.items()} df['inv_group'] = df['ph_name'].map(inv_group_map) df['acc_num'] = df['ph_name'].map(acc_num_map) # 方法2:使用apply一次性生成两列数据 df[['inv_group', 'acc_num']] = df['ph_name'].apply( lambda x: pd.Series(mapping.get(x, (np.nan, np.nan))) # 处理未匹配到的情况 )
这两种向量化操作处理2万多行数据仅需毫秒级,完全适配大数据量场景。
2. SettingWithCopyWarning警告的处理
该警告不能忽略,它通常由不良编码习惯导致,背后可能隐藏数据修改不生效的风险:
警告原因
你使用df[tgt1][x]这种链式索引的方式赋值,Pandas无法确定你修改的是原始DataFrame还是其切片副本。比如如果df是从另一个大DataFrame切片得到的(如df = big_df[big_df['col'] > 0]),链式赋值可能只会修改临时副本,原始数据不会同步更新,导致结果不符合预期。
解决方法
- 避免链式索引,改用
.loc进行显式定位赋值(即使保留循环,也应修改为以下写法):for x in df.index: if df.loc[x, 'ph_name'] == look1: df.loc[x, 'inv_group'] = 'MEMORIAL' df.loc[x, 'acc_num'] = 12345 # 其余elif逻辑同理修改 - 最彻底的解决方式是直接使用上述向量化方法,从根源上消除循环和链式索引的问题。
若确认df是原始DataFrame而非切片副本,可通过df.is_copy = None临时关闭警告,但不推荐这种做法——规范代码写法才是消除警告的根本方案。
内容的提问来源于stack exchange,提问作者user10097577
相关产品推荐
相关产品推荐

