Загрузить разреженный массив из файла 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, В противном случае я не нахожу никакого специального кода травления в разреженных файлах.

Другие вопросы по тегам