使用dask将许多MAT文件导入一个DataFrame

时间:2017-06-09 16:51:57

标签: python pandas hdf5 pytables dask

我有许多相同格式的mat文件,我希望将这些mat文件加入一个带有DatetimeIndex的DataFrame中。目前,for循环读取这些mat文件并使用scipy.io.loadmat将每个文件的内容加载到pandas DataFrame中,然后将每个DataFrame附加到hdf5表。

每个mat文件包含一个4096x1024单精度矩阵,最初每次循环迭代大约需要1.5秒。我用806个mat文件测试了这个(12.5GB需要大约25分钟),但是我想将这个应用到潜在的数百万个这些文件中,我有兴趣找到一个允许我导入新数据和查询的工作流和数据容器时间序列的子集很快。

是否可以使用dask或其他工具加速此导入过程并创建一个可查询的时间序列?

for rot_file in rotation_files:
    print(rot_file)
    time_stamps = pd.DataFrame(scipy.io.loadmat(rot_file)['LineInfo'][0][0][2][0])
    polar_image = pd.DataFrame(scipy.io.loadmat(rot_file)['PolarImage'])
    polar_image = polar_image.transpose()
    polar_image.index = time_stamps[0].apply(convert_to_python_datetime).values
    rot_id = time_stamps[0]
    rot_id_df = pd.DataFrame(len(polar_image)*[rot_id],columns=['rotation_id'], dtype='category')
    rot_id_df.index = polar_image.index
    polar_image.join(rot_id_df)
    polar_image.columns = [str(col_name) for col_name in polar_image.columns]
    polar_image.to_hdf('rot_data.h5', 'polar_image', format='table', append=True, complib='blosc', complevel=9)

似乎可以使用dask.delayed进行导入,但我不确定如何将其写入单个hdf文件。

1 个答案:

答案 0 :(得分:2)

为了查询数据,您不需要写入dask明确支持的数据格式。您可以按如下方式定义数据框:

def mat_to_dataframe(rot_file):
    time_stamps = pd.DataFrame(scipy.io.loadmat(rot_file)['LineInfo'][0][0][2][0])
    polar_image = pd.DataFrame(scipy.io.loadmat(rot_file)['PolarImage'])
    polar_image = polar_image.transpose()
    polar_image.index = time_stamps[0].apply(convert_to_python_datetime).values
    rot_id = time_stamps[0]
    rot_id_df = pd.DataFrame(len(polar_image)*[rot_id],columns=['rotation_id'], dtype='category')
    rot_id_df.index = polar_image.index
    polar_image.join(rot_id_df)
    polar_image.columns = [str(col_name) for col_name in polar_image.columns]
    return polar_image

from dask import delayed
import dask.dataframe as dd

parts = [delayed(mat_to_dataframe)(fn) for fn in matfiles_list]
df = dd.from_delayed(parts)

这是一个“懒惰”的数据框:您可以对其应用类似熊猫的计算,但这些仅在您调用.compute()时执行。如果matload进程持有python GIL,那么我建议使用分布式调度程序(即使在一台机器上)client = dask.distributed.Client()

如果您可以先验地了解每个部分的时间戳,那么您还可以divisions=提供from_delayed,这意味着如果您的查询对索引有过滤器,那么dask将知道哪些文件不需要加载。

如果要加载的流程很慢,并且您希望以更快的格式进行查询,请尝试df.to_hdfdf.to_parquet。每个选项都会影响您的表现。

请注意,使用time_stamps[0].apply(convert_to_python_datetime).values可能会更快地实现pd.to_datetime(time_stamps[0])