pandas按条件用for循环填充DataFrame列的异常排查
原代码问题说明
你的代码跑不出结果、逻辑不生效有三个核心问题:
- 逐行for循环遍历pandas列是极低效的写法:pandas是基于numpy的向量化运算设计的,纯Python层的逐行循环在数据量稍大(比如十万行以上的航班数据集)时,性能会比内置向量化方法差成百上千倍,这就是你跑几小时都没结果的直接原因。
Series.add()方法不会原地修改数据:pandas中绝大多数Series、DataFrame的运算方法都会返回一个新的对象,不会直接修改原数据,你代码里写的fdf['COMPENSATION'].add(xxx)既没有赋值接收返回值,也没有指定原地修改,就算循环跑完,COMPENSATION列也永远是你初始插入的0,完全不会变。- 映射规则和你给出的预期效果不匹配:你代码里写的15<延误时长≤30时给50补偿,但你给的样例中延误25的补偿是0,规则阈值和值的对应关系本身写错了。
正确高效实现
直接用pandas内置的分箱方法pd.cut()做区间映射,全程向量化运算,哪怕百万行数据也是毫秒级出结果,完全不需要循环。
首先根据你给出的样例反推正确的区间规则:
- 到达延误 ≤30分钟:补偿0
- 30分钟 < 到达延误 ≤60分钟:补偿50
- 60分钟 < 到达延误 ≤120分钟:补偿250
- 120分钟 < 到达延误 ≤180分钟:补偿500
- 到达延误 >180分钟:补偿1000
对应实现代码:
import pandas as pd # 定义分箱边界,区间为左开右闭 delay_bins = [-float('inf'), 30, 60, 120, 180, float('inf')] # 每个区间对应的补偿值,顺序和分箱区间一一对应 compensation_list = [0, 50, 250, 500, 1000] # 直接生成COMPENSATION列,不需要提前插入初始值 fdf['COMPENSATION'] = pd.cut( x=fdf['ARRIVAL_DELAY'], bins=delay_bins, labels=compensation_list ).astype('int64') # 将分箱返回的category类型转为整数类型
跑出来的结果和你给出的样例完全匹配:
| ARRIVAL_DELAY | COMPENSATION |
|---|---|
| 10 | 0 |
| 25 | 0 |
| 43 | 50 |
| 61 | 250 |
如果你的映射规则后续会加更多复杂判断,也可以用numpy.select实现,同样是向量化运算,性能和pd.cut接近:
import numpy as np # 按顺序写判断条件 cond_list = [ fdf['ARRIVAL_DELAY'] <= 30, (fdf['ARRIVAL_DELAY'] > 30) & (fdf['ARRIVAL_DELAY'] <= 60), (fdf['ARRIVAL_DELAY'] > 60) & (fdf['ARRIVAL_DELAY'] <= 120), (fdf['ARRIVAL_DELAY'] > 120) & (fdf['ARRIVAL_DELAY'] <= 180), fdf['ARRIVAL_DELAY'] > 180 ] # 条件对应的值 value_list = [0, 50, 250, 500, 1000] fdf['COMPENSATION'] = np.select(condlist=cond_list, choicelist=value_list)
写pandas代码时尽量避免写逐行遍历的for循环,绝大多数数据处理场景都有对应的内置向量化实现,性能差距通常是几小时和几毫秒的区别。另外注意pandas的运算方法默认不会修改原数据,必须将运算结果重新赋值给对应列才能生效。
内容的提问来源于stack exchange,提问作者imark
相关产品推荐
相关产品推荐

