Загрузить разреженный массив из файла npy
Я пытаюсь загрузить разреженный массив, который я ранее сохранил. Сохранение разреженного массива было достаточно простым. Попытка прочитать это, хотя это боль. scipy.load возвращает массив 0d вокруг моего разреженного массива.
import scipy as sp
A = sp.load("my_array"); A
array(<325729x325729 sparse matrix of type '<type 'numpy.int8'>'
with 1497134 stored elements in Compressed Sparse Row format>, dtype=object)
Чтобы получить разреженную матрицу, я должен сгладить массив 0d или использовать sp.asarray(A). Это кажется очень сложным способом сделать что-то. Достаточно ли умен Сципи, чтобы понять, что он загрузил разреженный массив? Есть ли лучший способ загрузить разреженный массив?
3 ответа
Функции mmwrite/ mmread в scipy.io могут сохранять / загружать разреженные матрицы в формате Matrix Market.
scipy.io.mmwrite('/tmp/my_array',x)
scipy.io.mmread('/tmp/my_array').tolil()
mmwrite
а также mmread
может быть, все, что вам нужно. Это хорошо проверено и использует известный формат.
Тем не менее, следующее может быть немного быстрее:
Мы можем сохранить координаты строки и столбца и данные в виде 1-мерных массивов в формате npz.
import random
import scipy.sparse as sparse
import scipy.io
import numpy as np
def save_sparse_matrix(filename,x):
x_coo=x.tocoo()
row=x_coo.row
col=x_coo.col
data=x_coo.data
shape=x_coo.shape
np.savez(filename,row=row,col=col,data=data,shape=shape)
def load_sparse_matrix(filename):
y=np.load(filename)
z=sparse.coo_matrix((y['data'],(y['row'],y['col'])),shape=y['shape'])
return z
N=20000
x = sparse.lil_matrix( (N,N) )
for i in xrange(N):
x[random.randint(0,N-1),random.randint(0,N-1)]=random.randint(1,100)
save_sparse_matrix('/tmp/my_array',x)
load_sparse_matrix('/tmp/my_array.npz').tolil()
Вот некоторый код, который предлагает сохранить разреженную матрицу в файле npz, может быть быстрее, чем использовать mmwrite/mmread:
def using_np_savez():
save_sparse_matrix('/tmp/my_array',x)
return load_sparse_matrix('/tmp/my_array.npz').tolil()
def using_mm():
scipy.io.mmwrite('/tmp/my_array',x)
return scipy.io.mmread('/tmp/my_array').tolil()
if __name__=='__main__':
for func in (using_np_savez,using_mm):
y=func()
print(repr(y))
assert(x.shape==y.shape)
assert(x.dtype==y.dtype)
assert(x.__class__==y.__class__)
assert(np.allclose(x.todense(),y.todense()))
доходность
% python -mtimeit -s'import test' 'test.using_mm()'
10 loops, best of 3: 380 msec per loop
% python -mtimeit -s'import test' 'test.using_np_savez()'
10 loops, best of 3: 116 msec per loop
Можно извлечь объект, скрытый в массиве 0d, используя () в качестве индекса:
A = sp.load("my_array")[()]
Это выглядит странно, но, похоже, все равно работает, и это очень короткий обходной путь.
За все последующие голоса mmwrite
ответ, я удивлен, никто не пытался ответить на актуальный вопрос. Но так как он был активирован, я попробую.
Это воспроизводит случай OP:
In [90]: x=sparse.csr_matrix(np.arange(10).reshape(2,5))
In [91]: np.save('save_sparse.npy',x)
In [92]: X=np.load('save_sparse.npy')
In [95]: X
Out[95]:
array(<2x5 sparse matrix of type '<type 'numpy.int32'>'
with 9 stored elements in Compressed Sparse Row format>, dtype=object)
In [96]: X[()].A
Out[96]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
In [93]: X[()].A
Out[93]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
In [94]: x
Out[94]:
<2x5 sparse matrix of type '<type 'numpy.int32'>'
with 9 stored elements in Compressed Sparse Row format
[()]
что user4713166 дал нам не "сложный способ" для извлечения разреженного массива.
np.save
а также np.load
предназначены для работы на ndarrays. Но разреженная матрица не является таким массивом и не является подклассом (как np.matrix
является). Похоже, что np.save
оборачивает объект без массива в object dtype array
и сохраняет его вместе с маринованной формой объекта.
Когда я пытаюсь сохранить объект другого типа, который невозможно обработать, я получаю сообщение об ошибке по адресу:
403 # We contain Python objects so we cannot write out the data directly.
404 # Instead, we will pickle it out with version 2 of the pickle protocol.
-> 405 pickle.dump(массив, fp, протокол =2)
Так что в ответ на Is Scipy smart enough to understand that it has loaded a sparse array?
нет np.load
не знает о разреженных массивах. Но np.save
достаточно умен, чтобы дать понять, когда ему дают что-то, кроме массива, и np.load
делает то, что может с тем, что, если находит в файле.
Что касается альтернативных методов сохранения и загрузки разреженных массивов, то io.savemat
, MATLAB-совместимый метод, уже упоминалось. Это был бы мой первый выбор. Но этот пример также показывает, что вы можете использовать обычный Python pickling
, Это может быть лучше, если вам нужно сохранить определенный разреженный формат. А также np.save
не плохо, если вы можете жить с [()]
шаг извлечения.:)
https://github.com/scipy/scipy/blob/master/scipy/io/matlab/mio5.pywrite_sparse
- разреженные сохраняются в csc
формат. Вместе с заголовками это экономит A.indices.astype('i4'))
, A.indptr.astype('i4'))
, A.data.real
и опционально A.data.imag
,
В быстрых тестах я обнаружил, что np.save/load
обрабатывает все разреженные форматы, кроме dok
, где load
жалуется на пропавшего без вести shape
, В противном случае я не нахожу никакого специального кода травления в разреженных файлах.