加载大型稀疏矩阵的最快方法

时间:2016-08-04 10:34:17

标签: python csv pandas pickle hdf

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

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

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

经过调查,我发现了这个帖子:Why does saving/loading data in python take a lot more space/time than matlab?

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

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

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那么快),但是大熊猫花了大约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)。

0 个答案:

没有答案