Pandas向700万行DataFrame添加少量行耗时过长问题排查
高效向大DataFrame添加少量行的解决方案
问题原因分析
pd.concat耗时久的核心原因:使用ignore_index=True时,pandas会为拼接后的新DataFrame重新生成连续索引,这需要复制700万行的全部数据并重新分配内存,带来巨大开销。df.loc首次插入慢的原因:DataFrame创建时会预分配固定大小的内存,首次插入超出当前行数的行时,会触发内存扩容操作——重新申请更大的内存块并复制原有所有数据,这就是首次插入耗时极长的原因,后续插入因内存已扩容,速度明显提升。
优化方案
方案1:避免索引重生成,手动对齐索引
通过为小DataFrame设置连续的后续索引,跳过ignore_index=True的全量索引重建:
import pandas as pd import datetime rootPath = '/fullPathHere/' start_time = datetime.datetime.now() df = pd.read_parquet(rootPath + 'HistoricData.parquet', engine='fastparquet') print(datetime.datetime.now() - start_time, len(df.index), 'DF read') start_time = datetime.datetime.now() df_csv = pd.read_csv(rootPath + 'Full.csv') # 确保小DF的列与大DF完全一致(避免列对齐开销) df_csv = df_csv[df.columns] print(datetime.datetime.now() - start_time, len(df_csv.index), 'CSV read') start_time = datetime.datetime.now() df = df.reset_index(drop=True) # 为小DF设置从大DF末尾开始的连续索引 df_csv.index = range(len(df), len(df) + len(df_csv)) print(datetime.datetime.now() - start_time, 'Index setup done') start_time = datetime.datetime.now() df = pd.concat([df, df_csv]) print(datetime.datetime.now() - start_time, 'concat done')
方案2:转字典列表后重构(最优少量行添加)
对于仅添加少量行的场景,将数据转为字典列表后扩展,再重构DataFrame,避免全量数据复制:
import pandas as pd import datetime rootPath = '/fullPathHere/' start_time = datetime.datetime.now() df = pd.read_parquet(rootPath + 'HistoricData.parquet', engine='fastparquet') print(datetime.datetime.now() - start_time, len(df.index), 'DF read') start_time = datetime.datetime.now() df_csv = pd.read_csv(rootPath + 'Full.csv') df_csv = df_csv[df.columns] print(datetime.datetime.now() - start_time, len(df_csv.index), 'CSV read') start_time = datetime.datetime.now() # 转成字典列表 full_data = df.to_dict('records') full_data.extend(df_csv.to_dict('records')) # 重构DataFrame df = pd.DataFrame(full_data) print(datetime.datetime.now() - start_time, 'Data merged done')
方案3:使用轻量内部方法(临时场景)
df.append已被官方弃用,但内部的_append方法实现更轻量,适合临时快速拼接:
# 替换concat或loc的步骤 df = df._append(df_csv, ignore_index=True)
关键注意事项
- 必须确保两个DataFrame的列名、数据类型完全一致,否则会触发列对齐的额外开销,甚至生成NaN值。可通过
df_csv = df_csv[df.columns]强制列顺序一致。 - 方案2的优势在于仅处理少量新增行,内存开销极低,通常能把耗时控制在0.1-0.5秒内。
内容的提问来源于stack exchange,提问作者ravishankarurp
相关产品推荐
相关产品推荐

