如何用Python高效合并1000+同格式CSV文件?
优化大体积CSV合并的Python方案
原代码慢的核心原因
每次循环执行pd.concat([combined_data, new_df])会反复复制已有数据,随着数据量累积,复制开销呈指数级增长,这是效率低下的关键。结合你集群内存充足的条件,以下是针对性优化方案:
优化方案1:先收集DataFrame列表,最后一次性合并
避免循环中反复复制数据,仅在最后执行一次合并,时间复杂度从O(n²)降至O(n):
import os import pandas as pd folder_path = 'Some path here' csv_files = [file for file in os.listdir(folder_path) if file.endswith('.csv')] # 定义统一数据类型:指定字符串列,其他数值列可按需明确(减少类型推断耗时) dtypes = {'stringbvariablename': str} # 示例:若明确其他列类型,可追加:dtypes.update({'col1': 'int64', 'col2': 'float64'}) df_list = [] for e, csv_file in enumerate(csv_files): print(f'Processing {e+1} out of {len(csv_files)}: {csv_file}') file_path = os.path.join(folder_path, csv_file) # 用C引擎加速读取,关闭低内存模式避免类型推断波动 df = pd.read_csv(file_path, dtype=dtypes, engine='c', low_memory=False) df_list.append(df) # 一次性合并所有数据 combined_data = pd.concat(df_list, ignore_index=True)
优化方案2:提前获取列类型,避免重复推断
利用格式一致的特点,先读取一个小文件获取完整列类型,批量复用减少每个文件的类型推断时间:
import os import pandas as pd folder_path = 'Some path here' csv_files = [file for file in os.listdir(folder_path) if file.endswith('.csv')] # 读取第一个文件提取全列类型 sample_file = os.path.join(folder_path, csv_files[0]) sample_df = pd.read_csv(sample_file, dtype={'stringbvariablename': str}) dtypes = sample_df.dtypes.to_dict() df_list = [] for e, csv_file in enumerate(csv_files): print(f'Processing {e+1} out of {len(csv_files)}: {csv_file}') file_path = os.path.join(folder_path, csv_file) df = pd.read_csv(file_path, dtype=dtypes, engine='c', low_memory=False) df_list.append(df) combined_data = pd.concat(df_list, ignore_index=True)
优化方案3:Dask并行读取(集群多核/多节点场景)
借助Dask自动并行处理文件读取,充分利用集群资源:
import dask.dataframe as dd import os folder_path = 'Some path here' dtypes = {'stringbvariablename': str} # 批量读取所有CSV,自动并行处理 dask_df = dd.read_csv(os.path.join(folder_path, '*.csv'), dtype=dtypes) # 内存充足时转为pandas DataFrame combined_data = dask_df.compute()
额外提速技巧
- 用
glob.glob(os.path.join(folder_path, '*.csv'))替代os.listdir,直接获取CSV路径更简洁。 - 去掉不必要的打印语句,减少IO开销。
- 用Polars替代Pandas,Polars的CSV读取速度普遍快于Pandas:
import polars as pl import os folder_path = 'Some path here' csv_files = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith('.csv')] combined_data = pl.concat([pl.read_csv(f, dtypes={'stringbvariablename': str}) for f in csv_files]).to_pandas()
内容的提问来源于stack exchange,提问作者phdstudent
相关产品推荐
相关产品推荐

