2

我一直在尝试寻找在 Python 中访问大型数据集的最快方法。

在我的真实案例中,我有一个大约 10,000 x 10,000 的 csv 文件,我将其加载到 pandas MultiIndex DataFrame 中,因为我主要采用点积并对级别求和。

由于将此 csv 加载到 pandas 大约需要一分钟,我一直在寻找提高速度的方法。

经过调查,我遇到了这个线程:为什么在 python 中保存/加载数据比 matlab 占用更多的空间/时间?

我从这个线程得到的是 .mat 文件加载速度更快,因为它们存储为 hdf5。因此,我想通过 h5py、pandas 和 scypio(从 .mat 文件加载数据)来评估 pickle 和 hdf 的性能。

我的真实世界案例的结果如下:

pickle 65.48222637176514
h5py 65.20841789245605
pandas 65.45801973342896
mat 20.857333660125732

可以看出,加载 .mat 文件确实比通过 Python 生成的 pickle 和 hdfs 快 3 倍以上。因此,.mat 文件的更快加载时间似乎不是由于 hdf,因为加载通过 python 生成的 hdfs 没有这个优势。

基于此,我想在这里发布一个问题,询问将大型数据集加载到 python 中最快的方法是什么。为此,我用一些随机数据制作了一个玩具示例:

import numpy as np
import pickle
import h5py
import pandas as pd

#create random numpy ndarray
array_foo = np.random.rand(10000,10000)

#save array to pickle
pickle.dump(array_foo, open('array_foo.pkl', 'wb'))

#save array to hdf through h5py
h5py_hdf_store = h5py.File('array_foo.h5')
h5py_hdf_store['array_foo'] = array_foo
h5py_hdf_store.close()

#save pandas to hdf
df = pd.DataFrame(array_foo)
df.to_hdf('df_foo.h5', 'df_foo')

#save to csv for conversion to mat
df.to_csv('df_foo.csv')

在 MATLAB 中将 csv 转换为 mat 后,我​​进行了以下测试来评估加载时间:

import pickle
import h5py
import pandas as pd
import scipy.io as sio
import time

#time pickle load
start_time = time.time()
pkl_array_foo = pickle.load(open('array_foo.pkl', 'rb'))
end_time = time.time()
delta_time = end_time - start_time
print('pickle', delta_time)

#time h5py load
start_time = time.time()
h5py_hdf_store = h5py.File('array_foo.h5')
h5py_array_foo = h5py_hdf_store['array_foo'][:,:]
end_time = time.time()
delta_time = end_time - start_time
print('h5py', delta_time)

#time pandas load
start_time = time.time()
df_array_foo = pd.read_hdf('df_foo.h5')
end_time = time.time()
delta_time = end_time - start_time
print('pandas', delta_time)

#time mat load
start_time = time.time()
dict_df_foo = sio.loadmat('mat_df_foo.mat')
mat_array_foo = dict_df_foo['mat_df_foo']
end_time = time.time()
delta_time = end_time - start_time
print('mat', delta_time)

结果如下:

pickle 68.21923732757568
h5py 67.92283535003662
pandas 67.95403552055359
mat 67.09603023529053

有趣的是,.mat 文件似乎在这里失去了加载优势。经过调查,事实证明现实世界的数据非常稀疏。为了弄清楚有多稀疏,我将所有非零值替换为 1,将所有值相加并除以矩阵的大小。这产生了约0.28的密度。使用这个数字,我将玩具示例中的随机矩阵替换为稀疏矩阵:

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
array_foo = array_foo_sparse.todense()

确实,这似乎起到了作用:

pickle 69.06890630722046
h5py 68.73687291145325
pandas 69.12291169166565
mat 22.53125286102295

因此,我想研究保存为稀疏是否可以加快 pickle、pandas 和 h5py 的加载时间。为此,我将稀疏版本直接保存到pickle,并保存了DataFrame的稀疏版本:

pickle.dump(array_foo_sparse, open('array_foo.pkl', 'wb'))
df_sparse = df.to_sparse()
df_sparse.to_hdf('df_foo.h5', 'df_foo')

尝试通过 h5py 保存时出现错误:

TypeError: Object dtype dtype('O') has no native HDF5 equivalent

经过一番调查,似乎我应该尝试使用分块存储,但我觉得通过进一步调查,我正在远离最初的目标。

结果如下:

pickle 38.300209283828735
pandas 470.5342836380005

虽然 pickle 似乎确实加快了速度(但仍然没有 .mat 快),但 pandas 受到了巨大的打击,加载需要将近 8 分钟。

最后我尝试直接从python保存到mat:

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
array_foo = array_foo_sparse.todense()

sio.savemat('array_foo.mat', {'array_foo':array_foo})

加载这个产生:

mat 73.23888158798218

并保存稀疏版本:

array_foo_sparse = sparse.random(10000,10000, density = 0.28)
sio.savemat('array_foo.mat', {'array_foo':array_foo_sparse})

产量

mat 29.749581336975098

虽然速度更快,但它仍然比 MATLAB 的 mat 文件慢了将近 10 秒。

因此,我想知道从这里去哪里。有什么方法可以达到(或超越)MATLAB mat 文件的性能?如果可能的话,我想留在同一个环境中(即python、spyder)。

4

0 回答 0