2011-06-08 2 views
9

Я пытаюсь загрузить разреженный массив, который я ранее сохранил. Сохранение разреженного массива было достаточно простым. Попытка прочитать его, хотя это боль. scipy.load возвращает массив 0d вокруг моего разреженного массива.Загрузка разреженного массива из файла npy

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) 

Для того, чтобы получить разреженную матрицу я должен выравнивать 0дн массив, или использовать sp.asarray (A). Это похоже на действительно трудный способ сделать что-то. Является ли Scipy достаточно умным, чтобы понять, что он загрузил разреженный массив? Есть ли лучший способ загрузить разреженный массив?

ответ

13

Функции в scipy.io могут сохранять/загружать разреженные матрицы в формате Matrix Market.

scipy.io.mmwrite('/tmp/my_array',x) 
scipy.io.mmread('/tmp/my_array').tolil()  

mmwrite и mmread может быть все, что вам нужно. Он хорошо протестирован и использует известный формат.

Тем не менее, следующий может быть немного быстрее:

Мы можем сохранить строки и столбцы координаты и данные, как 1-D массивы в формате 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 
+1

+1, 'scipy.io' является правильным решением. Я бы добавил, что если вы хотите спуститься по дороге оптимизации, вы можете рассмотреть «numpy.load (mmap_mode = 'r'/'c')'. Память, сопоставляющая файлы с диска, дает мгновенную загрузку ** и ** может сохранять память, так как один и тот же массив с отображением памяти может использоваться совместно несколькими процессами. – Radim

+0

scipy.io.savemat, вероятно, лучший – mathtick

+0

Использование np_savez вместо mm уменьшило время загрузки большой разреженной матрицы от 8min47 до 3s! Благодаря ! Я также попытался savez_compressed, но размер тот же, и время загрузки намного дольше. – MatthieuBizien

4

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

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

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

+0

Я уверен, вы также можете использовать .item(), но не цитируйте меня на этом :) – David

0

Для всех голосов 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 (массив, ∥f∥p, протокол = 2)

Так в ответ на Is Scipy smart enough to understand that it has loaded a sparse array?, no. np.load не знает о редких массивах.Но np.save достаточно умен, чтобы плутать при задании чего-то, что не является массивом, и np.load делает то, что может, с чем, если находит в файле.

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