2012-06-20 9 views
20

Ich habe Probleme beim Speichern einer numpy csr_matrix mit PyTables. Ich erhalte diese Fehlermeldung:Speichern von numpy spärlich Matrix 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 

Mein Code:

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() 

Irgendwelche Ideen?

Dank

+0

Sind Sie besorgt über die Größe der Daten auf der Festplatte? Ich denke, dass hdf5-Dateien in einem komprimierten Format gespeichert werden können. In diesem Fall könnten Sie nur die dichte Matrix speichern. – user545424

+2

Siehe http://stackoverflow.com/questions/8895120/using-pytables-which-ismore-efficient-scipy-sparse-or-numpy-dense-matrix, es sieht so aus, als ob es keine Pytables-Unterstützung für dünn besetzte Matrizen gibt. – user545424

Antwort

21

Eine CSR-Matrix vollständig aus seinen data, indices und indptr Attributen rekonstruiert werden kann. Dies sind nur reguläre numpige Arrays, daher sollte es kein Problem sein, sie als 3 separate Arrays in Pytables zu speichern und dann an den Konstruktor csr_matrix zurückzuleiten. Siehe scipy docs.

Edit: Pietro Antwort hat darauf hingewiesen, dass das shape Mitglied auch

gespeichert werden sollen
+0

Ich glaube, der Punkt ist jedoch, es wie eine dichte Matrix zu verwenden. Wie kann ich eine CSR_Matrix in eine PATABLE-Instanz mit "dichtem Format" konvertieren? – Will

+0

Sie können eine csr_matrix in ein dichtes Array konvertieren, indem Sie die Elementfunktion toarray verwenden, die dann in Pytables gespeichert werden kann. Natürlich kann dies möglicherweise viel Speicherplatz verschwenden, obwohl hdf5 Dateikomprimierungsoptionen hat, die helfen können. – DaveP

+1

NumPy 'toarray()' kann nicht mit der Umwandlung von riesigen in dichte umgehen. Ich hatte gehofft, die Tabelle direkt von CSR zu konstruieren. – Will

33

Die Antwort von DaveP ist fast Recht ... aber kann Probleme für sehr dünn besetzte Matrizen verursachen: wenn die letzte Spalte (s) oder Zeile (n) sind leer, sie werden fallengelassen. Damit alles funktioniert, muss auch das Attribut "shape" gespeichert werden.

Dies ist der Code, den ich regelmäßig verwenden:

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 

Es ist trivial es anzupassen Matrizen zu csc.

+0

Wie lautet die Variable 'name' in der obigen Antwort? – Rama

+1

@Rama: nur ein Schlüssel zum Speichern des Objekts. Beliebig, Sie brauchen es nur, um es zurück zu holen (in einem HDF-Speicher können Sie viele verschiedene Objekte speichern). –

6

Ich habe die ausgezeichnete Antwort Pietro Battiston für Python 3.6 und PyTables 3.x aktualisiert, da einige PyTables-Funktionsnamen beim Upgrade von 2.x geändert wurden.

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