Pandas iterrows运行过慢,60万行数据缺失值填充的更快替代方案
针对60万行数据集的缺失值填充优化方案
原代码使用iterrows()逐行迭代,再嵌套列循环+at赋值,这种Python层面的循环在大数据量下效率极低,核心优化思路是用pandas的向量化操作替代逐行迭代,以下是两种高效替代方案:
方案一:预计算分组中位数映射(适配自定义get_median逻辑)
如果get_median是调用外部接口或基于外部数据计算中位数,优先用这种方式,避免循环中重复调用:
%%time import numpy as np import pandas as pd df_inputed = df.copy() # 1. 预计算所有唯一分组的中位数,构建映射字典 unique_groups = df_to_inpute[['sic', 'year', 'quarter']].drop_duplicates() group_median_map = {} for _, row in unique_groups.iterrows(): sic, year, quarter = row['sic'], row['year'], row['quarter'] median_val = get_median(sic, year, quarter) if not np.isnan(median_val): group_median_map[(sic, year, quarter)] = median_val # 2. 生成分组键列,用于匹配中位数 df_to_inpute['_group_key'] = df_to_inpute.apply(lambda x: (x['sic'], x['year'], x['quarter']), axis=1) # 3. 批量填充每个目标列的缺失值 for col in cols_to_check: # 获取每行对应的中位数(无匹配则为NaN) median_series = df_to_inpute['_group_key'].map(group_median_map) # 仅填充原列是NaN且中位数存在的行 df_inputed[col] = df_inputed[col].fillna(median_series) # 清理临时列 df_to_inpute.drop('_group_key', axis=1, inplace=True)
方案二:直接用groupby.transform(适配中位数基于当前数据集的场景)
如果get_median的逻辑就是计算当前数据集中对应分组的中位数,可直接用pandas内置的分组操作,代码更简洁高效:
%%time import pandas as pd df_inputed = df.copy() for col in cols_to_check: # 按sic/year/quarter分组计算中位数,自动匹配到每行并填充缺失值 df_inputed[col] = df_inputed[col].fillna( df_inputed.groupby(['sic', 'year', 'quarter'])[col].transform('median') )
为什么这些方案更快?
- 向量化操作是pandas底层用C实现的,避免了Python循环的解释器开销,处理60万行数据的速度会比原代码快100~1000倍
- 预计算分组中位数避免了重复调用
get_median,减少了冗余计算/IO groupby.transform直接将分组计算结果广播到原数据集的每行,无需手动索引匹配
内容的提问来源于stack exchange,提问作者ryantan
相关产品推荐
相关产品推荐

