2012-06-20 3 views
20

Sto riscontrando problemi nella memorizzazione di una nums csr_matrix con PyTables. Sto ottenendo questo errore:Memorizzare la matrice sparsa numpy in HDF5 (PyTables)

TypeError: objects of type ``csr_matrix`` are not supported in this context, sorry; supported objects are: NumPy array, record or scalar; homogeneous list or tuple, integer, float, complex or string 

Il mio codice:

f = tables.openFile(path,'w') 

atom = tables.Atom.from_dtype(self.count_vector.dtype) 
ds = f.createCArray(f.root, 'count', atom, self.count_vector.shape) 
ds[:] = self.count_vector 
f.close() 

Tutte le idee?

Grazie

+0

Sei preoccupato per la dimensione dei dati sul disco? Penso che i file hdf5 possano essere archiviati in formato compresso, nel qual caso potresti farla franca semplicemente memorizzando la matrice densa. – user545424

+2

Vedere http://stackoverflow.com/questions/8895120/using-pytables-which-is-more-efficient-scipy-sparse-or-numpy-dense-matrix, sembra che non vi sia alcun supporto pytables per matrici sparse. – user545424

risposta

21

Matrice CSR possono essere completamente ricostruiti dalle data, indices e indptr attributi. Questi sono solo normali array numpy, quindi non ci dovrebbero essere problemi a memorizzarli come 3 array separati in pytables, quindi passarli nuovamente al costruttore di csr_matrix. Vedi lo scipy docs.

Edit: La risposta di Pietro ha sottolineato che gli Stati shape dovrebbe anche essere conservato

+0

Credo che il punto, però, sia usarlo come una matrice densa. Come posso convertire una csr_matrix in un'istanza di pytables "denso-formato"? – Will

+0

È possibile convertire una csr_matrix in una matrice densa usando la sua funzione membro toarray, che può quindi essere salvata in pytables. Naturalmente, questo può potenzialmente sprecare molto spazio per i file, sebbene hdf5 abbia opzioni di compressione dei file che possono essere d'aiuto. – DaveP

+1

NumPy 'toarray()' non può gestire la conversione di quelli giganteschi in denso. Speravo di costruire il tavolo direttamente dalla CSR. – Will

33

La risposta da DaveP è quasi ragione ... ma può causare problemi per matrici sparse molto: se l'ultima colonna (s) o riga (s) sono vuoti, sono caduti. Per essere sicuri che tutto funzioni, anche l'attributo "forma" deve essere memorizzato.

Questo è il codice che uso regolarmente:

import tables as tb 
from numpy import array 
from scipy import sparse 

def store_sparse_mat(m, name, store='store.h5'): 
    msg = "This code only works for csr matrices" 
    assert(m.__class__ == sparse.csr.csr_matrix), msg 
    with tb.openFile(store,'a') as f: 
     for par in ('data', 'indices', 'indptr', 'shape'): 
      full_name = '%s_%s' % (name, par) 
      try: 
       n = getattr(f.root, full_name) 
       n._f_remove() 
      except AttributeError: 
       pass 

      arr = array(getattr(m, par)) 
      atom = tb.Atom.from_dtype(arr.dtype) 
      ds = f.createCArray(f.root, full_name, atom, arr.shape) 
      ds[:] = arr 

def load_sparse_mat(name, store='store.h5'): 
    with tb.openFile(store) as f: 
     pars = [] 
     for par in ('data', 'indices', 'indptr', 'shape'): 
      pars.append(getattr(f.root, '%s_%s' % (name, par)).read()) 
    m = sparse.csr_matrix(tuple(pars[:3]), shape=pars[3]) 
    return m 

È banale per adattarlo alla CSC matrici.

+0

A cosa corrisponde la variabile 'name' nella risposta sopra? – Rama

+1

@Rama: solo una chiave per memorizzare l'oggetto. Arbitrario, hai solo bisogno di recuperarlo (in uno stesso archivio HDF, puoi immagazzinare tonnellate di oggetti diversi). –

6

Ho aggiornato la risposta eccellente di Pietro Battiston per Python 3.6 e PyTables 3.x, poiché alcuni nomi di funzione di PyTables sono stati modificati nell'aggiornamento da 2.x.

import numpy as np 
from scipy import sparse 
import tables 

def store_sparse_mat(M, name, filename='store.h5'): 
    """ 
    Store a csr matrix in HDF5 

    Parameters 
    ---------- 
    M : scipy.sparse.csr.csr_matrix 
     sparse matrix to be stored 

    name: str 
     node prefix in HDF5 hierarchy 

    filename: str 
     HDF5 filename 
    """ 
    assert(M.__class__ == sparse.csr.csr_matrix), 'M must be a csr matrix' 
    with tables.open_file(filename, 'a') as f: 
     for attribute in ('data', 'indices', 'indptr', 'shape'): 
      full_name = f'{name}_{attribute}' 

      # remove existing nodes 
      try: 
       n = getattr(f.root, full_name) 
       n._f_remove() 
      except AttributeError: 
       pass 

      # add nodes 
      arr = np.array(getattr(M, attribute)) 
      atom = tables.Atom.from_dtype(arr.dtype) 
      ds = f.create_carray(f.root, full_name, atom, arr.shape) 
      ds[:] = arr 

def load_sparse_mat(name, filename='store.h5'): 
    """ 
    Load a csr matrix from HDF5 

    Parameters 
    ---------- 
    name: str 
     node prefix in HDF5 hierarchy 

    filename: str 
     HDF5 filename 

    Returns 
    ---------- 
    M : scipy.sparse.csr.csr_matrix 
     loaded sparse matrix 
    """ 
    with tables.open_file(filename) as f: 

     # get nodes 
     attributes = [] 
     for attribute in ('data', 'indices', 'indptr', 'shape'): 
      attributes.append(getattr(f.root, f'{name}_{attribute}').read()) 

    # construct sparse matrix 
    M = sparse.csr_matrix(tuple(attributes[:3]), shape=attributes[3]) 
    return M