如何高效遍历PhysioNet 2019文件并合并为单个DataFrame
PhysioNet 2019数据集合并代码优化
问题描述
我拥有PhysioNet 2019数据集,包含约40000份患者记录,每个文件对应一位患者,需要将所有数据合并为单个DataFrame。我了解到循环中不应直接拼接pandas DataFrame,应先存入列表再转换,但当前用np.append循环拼接numpy数组时,初期每秒100次迭代,后期仅5次/秒。请问能否优化代码?是否应改用普通Python列表替代numpy数组?
原有代码
for directory in tqdm(os.listdir(dir_path)): for file in tqdm(os.listdir(dir_path + '/'+ directory)): pat_path = dir_path + '/'+ directory + '/'+ file new_pat = pd.read_csv(pat_path,sep='|') new_pat['PatID'] = file[1:-4] new_pat = new_pat.to_numpy() physionet_2019 = np.append(physionet_2019, new_pat, axis=0) physionet_2019 = pd.DataFrame(physionet_2019, columns= column_names)
问题根源
np.append每次调用都会创建一个新的numpy数组,将原有数组和新数据全部复制进去。随着数组体积不断增大,每次复制的时间成本会急剧上升,这就是后期迭代速度暴跌的核心原因。
优化方案
改用普通Python列表存储每个患者的数据(直接存DataFrame或numpy数组均可),因为列表的append操作是均摊O(1)时间复杂度,不会每次复制全部数据,最后再一次性合并,效率会大幅提升。
方案1:直接存储DataFrame(最简洁高效)
import os import pandas as pd from tqdm import tqdm dir_path = "你的数据集路径" column_names = ["你的列名列表"] # 初始化列表存储每个患者的DataFrame data_list = [] for directory in tqdm(os.listdir(dir_path)): dir_full_path = os.path.join(dir_path, directory) for file in tqdm(os.listdir(dir_full_path)): pat_path = os.path.join(dir_full_path, file) new_pat = pd.read_csv(pat_path, sep='|') new_pat['PatID'] = file[1:-4] data_list.append(new_pat) # 一次性合并所有DataFrame physionet_2019 = pd.concat(data_list, ignore_index=True)
方案2:存储numpy数组后合并
如果坚持用numpy数组,也可以先存入列表,最后用np.vstack一次性拼接:
import os import numpy as np import pandas as pd from tqdm import tqdm dir_path = "你的数据集路径" column_names = ["你的列名列表"] data_list = [] for directory in tqdm(os.listdir(dir_path)): dir_full_path = os.path.join(dir_path, directory) for file in tqdm(os.listdir(dir_full_path)): pat_path = os.path.join(dir_full_path, file) new_pat = pd.read_csv(pat_path, sep='|') new_pat['PatID'] = file[1:-4] data_list.append(new_pat.to_numpy()) # 一次性拼接所有数组 physionet_2019 = np.vstack(data_list) physionet_2019 = pd.DataFrame(physionet_2019, columns=column_names)
额外优化建议
- 使用
os.path.join拼接路径,避免手动拼接字符串出现的路径分隔符问题 - 若机器性能允许,可使用
tqdm.contrib.concurrent.process_map实现并行读取,进一步提升速度
内容的提问来源于stack exchange,提问作者Ali Fayad
相关产品推荐
相关产品推荐

