我有一个庞大的2d numpy数组,它可以作为共生矩阵运行。我曾尝试使用scipy.sparse作为我的数据结构,但dok_matrix
索引速度非常慢(慢4倍)。
# Impossible
import numpy
N = 1000000 (1 milion)
coo = np.zeros((N, N), dtype=np.uint32)
我想坚持这个数组。
在搜索保存方法后,我尝试使用PyTables
或hd5py
,但我找不到一种方法来保存它而不会耗尽内存。
with open(name, 'w') as _file:
np.save(_file, coo)
例如,使用PyTables
:
import tables
_file = tables.openFile(
name,
mode='w',
title='Co-occurrence matrix')
atom = tables.Atom.from_dtype(coo.dtype)
_filters = tables.Filters(complib='blosc', complevel=5)
ds = _file.createEArray(
_file.root,
'coo_matrix',
atom,
shape=(0, coo.shape[-1]),
expectedrows=coo.shape[-1],
filters=_filters)
# ds[:] = coo => not an option
for _index, _data in enumerate(coo):
ds.append(coo[_index][np.newaxis,:])
_file.close()
使用hd5py
:
import h5py
h5f = h5py.File(name, 'w')
h5f.create_dataset('dataset_1', data=coo)
这两种方法都会增加内存使用量,直到我必须终止进程。那么,有没有办法逐步增加?如果不能这样做,你能推荐另一种方法来保持这个矩阵吗?
修改
我正在创建这样的共生矩阵:
coo = np.zeros((N, N), dtype=np.uint32)
for doc_id, doc in enumerate(self.w.get_docs()):
for w1, w2 in combinations(doc, 2):
if w1 != w2:
coo[w1, w2] += 1
我想保存coo(2d numpy数组)以便稍后从磁盘中检索它并找到共现值,例如:coo [w1,w2]
答案 0 :(得分:0)
np.save
是一种快速有效的保存密集阵列的方法。它所做的只是写一个小标题,然后是数组的数据缓冲区。
但对于大型数组,该数据缓冲区将在一个连续的内存块中具有N*N*4
(对于您的dtype)字节。该设计也适用于元素访问 - 代码确切地知道i,j
元素的位置。
请注意np.zeros((N,N))
不会立即分配所有必要的内存。内存使用可能会在使用过程中增长(包括保存)
np.savez
对数据存储没有帮助。它为每个变量执行save
,并在zip存档(也可以压缩)中收集生成的文件。
表和h5py可以保存和加载块,但是如果你必须在某个时刻使用整个数组 - 无论是创建还是使用它都没有帮助。
由于您的数组非常稀疏,因此scipy
稀疏矩阵可以节省内存,因为它只存储非零元素。但它也必须存储该元素的坐标,因此每个非零元素的存储不是紧凑的。有许多格式,每种格式都有其优缺点。
dok
使用Python字典来存储数据,其格式为(i,j)
。它是逐步构建稀疏矩阵的更好格式之一。我在其他SO问题中发现使用dok
的元素访问比使用普通字典慢。构建常规字典更快,然后update
dok
。
lil
是增量构建的另一种好格式。它将数据存储在2个列表中。
coo
数组, i,j,data
便于构建矩阵。
csr
和csc
适用于计算(尤其是线性代数种类)和元素访问。但是没有改变稀疏性的好处(添加非零元素)。
但是您可以使用一种格式构建矩阵,并可以将其转换为另一种格式以供使用或存储。
存在关于存储稀疏矩阵的SO问题。最简单的是使用MATLAB兼容的.mat格式(稀疏的csc
)。要使用np.save
,您需要保存基础数组(适用于coo
,csc
,csr
格式)。 Python pickle必须用于保存dok
或lil
。
搜索[scipy] large sparse
以查看有关此类矩阵的其他SO问题。你并不是第一个使用numpy / scipy来共同计算文档的人(它是scipy稀疏的三个主要用途之一,其他是线性代数和机器学习)。