2015-10-16 2 views
2

J'ai un énorme tableau numd 2d qui est censé fonctionner comme une matrice de co-occurrence. J'ai essayé d'utiliser scipy.sparse comme structure de données, mais l'indexation dok_matrix est incroyablement lente (4x fois plus lente).Python: Comment enregistrer 2d tableau numpy efficacement sur le disque?

# Impossible 
import numpy 
N = 1000000 (1 milion) 
coo = np.zeros((N, N), dtype=np.uint32) 

Je souhaite conserver ce tableau. Après avoir cherché des façons de le sauvegarder, j'ai essayé d'utiliser PyTables ou hd5py, mais je n'ai pas trouvé un moyen de l'enregistrer sans manquer de mémoire.

with open(name, 'w') as _file: 
    np.save(_file, coo) 

Par exemple, en utilisant PyTables:

import tables 
    _file = tables.openFile(
       name, 
       mode='w', 
       title='Co-occurrence matrix') 
    atom = tables.Atom.from_dtype(coo.dtype) 
    _filters = tables.Filters(complib='blosc', complevel=5) 
    ds = _file.createEArray(
      _file.root, 
      'coo_matrix', 
      atom, 
      shape=(0, coo.shape[-1]), 
      expectedrows=coo.shape[-1], 
      filters=_filters) 
    # ds[:] = coo => not an option 
    for _index, _data in enumerate(coo): 
     ds.append(coo[_index][np.newaxis,:]) 
    _file.close() 

Et en utilisant hd5py:

import h5py 
h5f = h5py.File(name, 'w') 
h5f.create_dataset('dataset_1', data=coo) 

Les deux méthodes ne cessent d'augmenter l'utilisation de la mémoire jusqu'à ce que je dois tuer le processus. Alors, y a-t-il un moyen de le faire progressivement? Si ce n'est pas possible, pouvez-vous recommander un autre moyen de persister dans cette matrice?

EDIT

Je crée cette matrice de co-occurrence comme ceci:

coo = np.zeros((N, N), dtype=np.uint32) 
    for doc_id, doc in enumerate(self.w.get_docs()): 
     for w1, w2 in combinations(doc, 2): 
       if w1 != w2: 
        coo[w1, w2] += 1 

Je veux sauver coo (2d tableau de numpy) pour le récupérer à partir du disque plus tard et trouver des valeurs de cooccurrences , comme: coo [w1, w2]

+0

Juste pour satisfaire ma propre curiosité: qu'est-ce que * chargement postérieur *? –

+0

En plus de stocker ce que vous essayez de faire avec ce tableau? Changer les valeurs individuelles, y accéder, accéder aux tranches, maths? – hpaulj

+0

Il existe l'option ['np.savez_compressed'] (http://stackoverflow.com/a/18232374/832621), qui est très rapide et compacte pour déplacer les données ... –

Répondre

0

np.save est un moyen rapide et efficace d'enregistrer un tableau dense. Tout ce qu'il fait est d'écrire un petit en-tête puis le tampon de données du tableau. Mais pour un grand tableau, ce tampon de données aura N*N*4 (pour votre dtype) octets - dans un bloc de mémoire contigu. Cette conception est également bonne pour l'accès aux éléments - le code sait exactement où se trouve l'élément i,j.

Notez que np.zeros((N,N)) n'alloue pas toute la mémoire nécessaire à la fois. L'utilisation de mémoire peut augmenter pendant l'utilisation (y compris l'enregistrement)

np.savez ne aide pas avec le stockage de données. Il effectue un save pour chaque variable et collecte les fichiers résultants dans une archive zip (qui peut également être compressée).

Les tables et h5py peuvent sauvegarder et charger des morceaux, mais cela n'aide pas si vous devez avoir un tableau entier dans la même chose à un moment donné - pour la création ou l'utilisation.

Étant donné que votre baie sera très clairsemée, une matrice creuse scipy pourrait économiser de la mémoire, car elle ne stocke que les éléments non nuls. Mais il doit également stocker les coordonnées de cet élément, de sorte que le stockage par élément non nul n'est pas aussi compact. Il y a un certain nombre de formats, chacun avec ses avantages et ses inconvénients.

dok utilise un dictionnaire Python pour stocker des données, avec des clés de la forme (i,j). C'est l'un des meilleurs formats pour construire progressivement une matrice clairsemée. J'ai trouvé dans d'autres questions SO que l'accès aux éléments avec un dok est plus lent qu'avec un dictionnaire simple.Il est plus rapide de construire un dictionnaire régulier, puis update le dok.

lil est un autre bon format pour les constructions incrémentielles. Il stocke les données dans 2 listes de listes.

coo est pratique pour construire une matrice, une fois que vous avez un ensemble complet de tableaux i,j,data. Sont bons pour le calcul (en particulier les types algébriques linéaires), et pour l'accès aux éléments. Mais pas bon pour changer la parcimonie (en ajoutant des éléments non-zéro).

Mais vous pouvez créer une matrice dans un format et la convertir facilement en une autre pour l'utiliser ou la stocker.

Il y a eu des questions sur le stockage de matrices creuses. Le plus simple est avec le format .mat compatible MATLAB (csc pour sparse). Pour utiliser np.save vous devez enregistrer les tableaux sous-jacents (pour les formats coo, csc, csr). Python pickle doit être utilisé pour enregistrer dok ou lil.

Faites une recherche sur [scipy] large sparse pour voir d'autres questions SO sur ce type de matrice. Vous n'êtes pas le premier à utiliser numpy/scipy pour les calculs de cooccurrence de documents (c'est l'un des 3 usages principaux de scipy sparse, les autres étant l'algèbre linéaire et l'apprentissage automatique).