web-dev-qa-db-fra.com

Scipy clairsemés ... tableaux?

Donc, je fais une classification Kmeans en utilisant des tableaux numpy qui sont assez clairsemés - beaucoup, beaucoup de zéros. Je me suis dit que j'utiliserais le paquet "clairsemé" de scipy pour réduire la surcharge de stockage, mais je suis un peu confus quant à la façon de créer des tableaux, pas des matrices.

J'ai parcouru ce tutoriel sur la façon de créer des matrices clairsemées: http://www.scipy.org/SciPy_Tutorial#head-c60163f2fd2bab79edd94be43682414f18b90df7

Pour imiter un tableau, je crée simplement une matrice 1xN, mais comme vous pouvez le deviner, Asp.dot (Bsp) ne fonctionne pas tout à fait parce que vous ne pouvez pas multiplier deux matrices 1xN. Je devrais transposer chaque tableau en Nx1, et c'est assez boiteux, car je le ferais pour chaque calcul de produit scalaire.

Ensuite, j'ai essayé de créer une matrice NxN où la colonne 1 == ligne 1 (de sorte que vous pouvez multiplier deux matrices et simplement prendre le coin supérieur gauche comme produit scalaire), mais cela s'est avéré vraiment inefficace.

J'adorerais utiliser le paquet clairsemé de scipy comme remplacement magique du tableau de numpy (), mais pour l'instant, je ne sais pas vraiment quoi faire.

Aucun conseil?

48
spitzanator

Utilisez un format scipy.sparse Basé sur une ligne ou une colonne: csc_matrix Et csr_matrix.

Ceux-ci utilisent des implémentations C efficaces sous le capot (y compris la multiplication), et la transposition est un no-op (en particulier si vous appelez transpose(copy=False)), tout comme avec les tableaux numpy.

EDIT: quelques timings via ipython :

import numpy, scipy.sparse
n = 100000
x = (numpy.random.Rand(n) * 2).astype(int).astype(float) # 50% sparse vector
x_csr = scipy.sparse.csr_matrix(x)
x_dok = scipy.sparse.dok_matrix(x.reshape(x_csr.shape))

Maintenant, x_csr Et x_dok Sont à 50% clairsemés:

print repr(x_csr)
<1x100000 sparse matrix of type '<type 'numpy.float64'>'
        with 49757 stored elements in Compressed Sparse Row format>

Et les horaires:

timeit numpy.dot(x, x)
10000 loops, best of 3: 123 us per loop

timeit x_dok * x_dok.T
1 loops, best of 3: 1.73 s per loop

timeit x_csr.multiply(x_csr).sum()
1000 loops, best of 3: 1.64 ms per loop

timeit x_csr * x_csr.T
100 loops, best of 3: 3.62 ms per loop

Il semble donc que j'ai menti. La transposition est très bon marché, mais il n'y a pas d'implémentation C efficace de csr * csc (dans le dernier scipy 0.9.0). Un nouvel objet csr est construit à chaque appel :-(

En tant que hack (bien que scipy soit relativement stable de nos jours), vous pouvez faire le produit scalaire directement sur les données éparses:

timeit numpy.dot(x_csr.data, x_csr.data)
10000 loops, best of 3: 62.9 us per loop

Notez que cette dernière approche fait à nouveau une multiplication dense numpy. La rareté est de 50%, donc elle est en fait plus rapide que dot(x, x) d'un facteur 2.

34
Radim

Vous pouvez créer une sous-classe de l'un des tableaux clairsemés 2D existants

from scipy.sparse import dok_matrix

class sparse1d(dok_matrix):
    def __init__(self, v):
        dok_matrix.__init__(self, (v,))
    def dot(self, other):
        return dok_matrix.dot(self, other.transpose())[0,0]

a=sparse1d((1,2,3))
b=sparse1d((4,5,6))
print a.dot(b)
1
John La Rooy

Je ne suis pas sûr que ce soit vraiment beaucoup mieux ou plus rapide, mais vous pouvez le faire pour éviter d'utiliser la transposition:

Asp.multiply(Bsp).sum()

Cela prend simplement le produit élément par élément des deux matrices et additionne les produits. Vous pouvez créer une sous-classe de n'importe quel format de matrice que vous utilisez qui a la déclaration ci-dessus comme produit scalaire.

Cependant, il est probablement plus simple de les transposer:

Asp*Bsp.T

Cela ne semble pas tellement faire, mais vous pouvez également créer une sous-classe et modifier la méthode mul ().

1
Justin Peel