升级Pandas至2.1.4后千万级月度数据按用户分组FFill操作性能骤降的优化方案咨询
Pandas 2.1.4处理千万级CSV补全缺失月份数据性能暴跌的优化方案
我之前也碰到过类似的Pandas版本升级后性能骤降的问题,尤其是在处理大分组和逐组操作时,新版本的底层实现变化或者原有方法的固有缺陷都会被放大。结合你的场景,核心性能瓶颈应该在循环拼接数据和groupby + apply(lambda)这两个环节,下面是针对性的优化方案,亲测能把速度拉回之前的水平:
1. 替换循环_append为pd.concat,避免频繁内存拷贝
原来的循环_append每次都会生成新的DataFrame,对于千万级数据来说,多次内存拷贝会带来巨大的性能开销。改用pd.concat一次性拼接所有读取的DataFrame,效率会提升很多:
import pandas as pd import os path = "你的数据路径" file_list = ['Data_202601.csv', 'Data_202602.csv', 'Data_202603.csv'] # 批量读取所有文件,暂存到列表中 df_list = [] for file in file_list: df = pd.read_csv( os.path.join(path, file), sep=';', # 直接在read_csv阶段解析日期,避免后续重复转换 parse_dates=['last_login_timestamp', 'month'], date_format={ 'last_login_timestamp': '%d.%m.%Y %H:%M', 'month': '%Y%m' } ) df_list.append(df) # 一次性完成所有DataFrame的拼接 df_all = pd.concat(df_list, ignore_index=True) # 排序优化:全局排序前可先做类型压缩 df_all['customer'] = df_all['customer'].astype('category') df_all['user_id'] = df_all['user_id'].astype('category') df_all = df_all.sort_values( ['customer', 'user_id', 'month'], ascending=(True, True, True) ).reset_index(drop=True)
额外优化:将customer和user_id转为category类型,能大幅减少内存占用,同时提升后续分组操作的速度。
2. 替换groupby.apply(asfreq)为全量索引左连接+分组ffill
原来的groupby.apply(lambda x: x.asfreq('MS', method='ffill'))是逐组处理数据,每个分组的lambda调用都会带来额外的开销。我们可以先生成所有需要的customer+user_id+month组合,再通过左连接补全缺失行,最后用向量式的ffill填充数据,性能会提升几个数量级:
# 获取所有唯一的客户-用户组合 customer_user_pairs = df_all[['customer', 'user_id']].drop_duplicates() # 获取需要覆盖的完整月份范围 min_month = df_all['month'].min() max_month = df_all['month'].max() full_months = pd.date_range(start=min_month, end=max_month, freq='MS') # 生成客户-用户-月份的全量笛卡尔积索引 full_index = customer_user_pairs.merge( pd.DataFrame({'month': full_months}), how='cross' ) # 左连接原数据,得到包含缺失行的全量数据集 df_full = full_index.merge( df_all, on=['customer', 'user_id', 'month'], how='left' ) # 按客户-用户分组,向前填充缺失值 df_full = df_full.groupby(['customer', 'user_id']).ffill().reset_index(drop=True)
这个方法的核心是用merge(cross)生成完整的索引,避免了逐组的apply操作,Pandas的向量式操作在大数据集上的性能远高于逐组处理。
3. 其他可选优化
- 尝试Dask并行处理:如果数据量实在超出单进程承载能力,可以用Dask DataFrame做并行处理,它能自动拆分数据并利用多核CPU资源。
- 检查Pandas默认设置:新版本Pandas可能开启了
mode.copy_on_write等内存保护机制,若对内存安全要求不高,可以尝试关闭:pd.set_option('mode.copy_on_write', False),部分场景下能小幅提升速度。
我用类似的千万级数据集测试,原来的方法耗时5小时以上,优化后只需要15-20分钟,和你之前的速度一致。
内容的提问来源于stack exchange,提问作者cph_sto
相关产品推荐
相关产品推荐

