Загрузить разреженный массив из файла npy - PullRequest
10 голосов
/ 08 июня 2011

Я пытаюсь загрузить разреженный массив, который я ранее сохранил.Сохранение разреженного массива было достаточно простым.Попытка прочитать это, хотя это боль.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 ]

15 голосов
/ 08 июня 2011

Функции 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
5 голосов
/ 25 марта 2015

Можно извлечь объект, скрытый в массиве 0d, используя () в качестве индекса:

A = sp.load("my_array")[()]

Это выглядит странно, но, похоже, все равно работает, и это очень короткий обходной путь.

0 голосов
/ 26 марта 2015

При всех голосах за ответ 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.py write_sparse - разреженные сохраняются в формате csc. Вместе с заголовками сохраняются A.indices.astype('i4')), A.indptr.astype('i4')), A.data.real и, опционально, A.data.imag.


В быстрых тестах я обнаружил, что np.save/load обрабатывает все разреженные форматы, кроме dok, где load жалуется на отсутствие shape. В противном случае я не нахожу никакого специального кода для травления в разреженных файлах.

...