Pandas千万级DataFrame合并及自定义列生成的优化方法咨询
嘿,处理1200万条级别的Pandas数据确实容易碰到性能瓶颈,我来给你分享几个亲测有效的优化方案,针对你遇到的两个问题分别拆解:
优化左连接合并的方案
针对你用merge耗时140分钟的问题,试试这几个方向:
- 先统一ID列的数据类型:如果你的ID列是
object(字符串)类型,但实际是整数,先转换成int类型能大幅提升匹配效率:
Pandas对整数的哈希和匹配速度远快于字符串,这一步是很多人容易忽略的关键优化点。name['ID'] = name['ID'].astype(int) purchase['ID'] = purchase['ID'].astype(int) - 基于索引进行合并:Pandas的
join方法(基于索引)比merge(基于列)在大数据量下效率更高。先把两个表的ID设为索引再合并:
最后用name_indexed = name.set_index('ID') purchase_indexed = purchase.set_index('ID') mergedDF = name_indexed.join(purchase_indexed, how='left').reset_index()reset_index()把ID重新放回列里,不影响后续操作。 - 排查重复ID避免笛卡尔积:如果两个表中存在大量重复的ID,merge时会生成笛卡尔积,不仅慢还会爆内存。可以先对表去重(业务允许的前提下):
name = name.drop_duplicates(subset='ID') purchase = purchase.drop_duplicates(subset='ID') - 用Dask做并行分块处理:如果内存吃紧,试试Dask这个并行计算库,它能把数据分成小块处理,语法和Pandas几乎一致,学习成本低:
import dask.dataframe as dd # 从Pandas DataFrame转换为Dask DataFrame,npartitions根据CPU核心数调整 name_dd = dd.from_pandas(name, npartitions=4) purchase_dd = dd.from_pandas(purchase, npartitions=4) merged_dd = name_dd.merge(purchase_dd, how='left', on='ID') mergedDF = merged_dd.compute() # 把Dask结果转回Pandas
优化自定义'key'列生成的方案
你用apply(lambda x: ..., axis=1)的方式是逐行遍历,1200万条数据相当于循环1200万次,速度肯定慢到离谱,换成矢量操作就能解决:
- 直接用矢量字符串拼接:Pandas的字符串列支持批量拼接,不用逐行处理,速度提升几个数量级:
如果ID已经是字符串类型,直接拼接就行,完全不需要apply。# 先把ID转成字符串(如果ID是整数类型的话) mergedDF['key'] = mergedDF['ID'].astype(str) + '&' + mergedDF['Product'] - 内存紧张时用Dask的矢量操作:和合并一样,Dask也支持这种批量字符串操作,分块处理不会占用过多内存:
merged_dd['key'] = merged_dd['ID'].astype(str) + '&' + merged_dd['Product'] mergedDF = merged_dd.compute()
额外的通用优化建议
- 用高效的数据格式存储:如果数据是从CSV读取的,换成Parquet或Feather格式,读取和处理速度会快很多,还能节省空间:
# 保存为Parquet name.to_parquet('name_data.parquet') purchase.to_parquet('purchase_data.parquet') # 读取 name = pd.read_parquet('name_data.parquet') purchase = pd.read_parquet('purchase_data.parquet') - 确保内存充足:处理1200万条数据,最好保证内存是数据大小的2-3倍,不然Pandas会启用虚拟内存,速度会暴跌。
内容的提问来源于stack exchange,提问作者Kshitij Yadav
相关产品推荐
相关产品推荐

