web-dev-qa-db-fra.com

Utilisation d'une matrice clairsemée par rapport au tableau numpy

Je crée des tableaux numpy avec des nombres de mots en Python: les lignes sont des documents, les colonnes sont des nombres pour Word X. Si j'ai beaucoup de nombres zéro, les gens suggèrent d'utiliser des matrices clairsemées lors de leur traitement ultérieur, par exemple dans un classificateur. Lors de l'alimentation d'un tableau numpy par rapport à une matrice clairsemée dans le Scikit classificateur de régression logistique , cela ne semblait pas faire beaucoup de différence, cependant. Je me posais donc trois questions:

  • Wikipedia dit

    une matrice clairsemée est une matrice dans laquelle la plupart des éléments sont nuls

    Est-ce une façon appropriée de déterminer quand utiliser un format matriciel clairsemé - dès que> 50% des valeurs sont nulles? Ou est-il judicieux d'utiliser au cas où?

  • Dans quelle mesure une matrice clairsemée améliore-t-elle les performances dans une tâche comme la mienne, en particulier par rapport à un tableau numpy ou à une liste standard?
  • Jusqu'à présent, je collecte mes données dans un tableau numpy, puis les convertis en csr_matrix dans Scipy . Est-ce la bonne façon de procéder? Je ne pouvais pas comprendre comment construire une matrice clairsemée à partir de zéro, et cela pourrait être impossible.

Toute aide est très appréciée!

14
patrick

Le package de matrice clairsemée scipy, et d'autres similaires dans MATLAB, était basé sur des idées développées à partir de problèmes d'algèbre linéaire, tels que la résolution de grandes équations linéaires clairsemées (par exemple, implémentations de différences finies et d'éléments finis). Des choses comme le produit matriciel (le produit dot pour les tableaux numpy) et les solveurs d'équations sont bien développées.

Mon expérience approximative est qu'un produit matriciel csr clairsemé doit avoir une densité de 1% pour être plus rapide que l'opération dense dot équivalente - en d'autres termes, une valeur non nulle pour 99 zéros. (mais voir les tests ci-dessous)

Mais les gens essaient également d'utiliser des matrices clairsemées pour économiser de la mémoire. Mais gardez à l'esprit qu'une telle matrice doit stocker 3 tableaux de valeurs (au moins au format coo). Donc, la rareté doit être inférieure à 1/3 pour commencer à économiser de la mémoire. De toute évidence, vous n'allez pas économiser de la mémoire si vous construisez d'abord le tableau dense et en créez un clairsemé à partir de cela.

Le package scipy implémente de nombreux formats clairsemés. Le format coo est le plus facile à comprendre et à créer. Créez-en un selon la documentation et regardez son .data, .row, et .col attributs (tableaux 3 1d).

csr et csc sont généralement construits à partir du format coo et compressent un peu les données, ce qui les rend un peu plus difficiles à comprendre. Mais ils ont la plupart des fonctionnalités mathématiques.

Il est également possible d'indexer le format csr, bien qu'en général cela soit plus lent que le cas de matrice/tableau dense équivalent. D'autres opérations comme la modification des valeurs (en particulier de 0 à non nul), la concaténation, la croissance incrémentielle, sont également plus lentes.

lil (listes de listes) est également facile à comprendre et idéal pour la construction incrémentielle. dok est en fait une sous-classe de dictionnaire.

Un point clé est qu'une matrice clairsemée est limitée à 2d et se comporte à bien des égards comme le np.matrix classe (bien qu'il ne s'agisse pas d'une sous-classe).

Une recherche d'autres questions en utilisant scikit-learn et sparse pourraient être le meilleur moyen de trouver les avantages/inconvénients de l'utilisation de ces matrices. J'ai répondu à un certain nombre de questions, mais je connais mieux le côté "clairsemé" que le côté "apprendre". Je pense qu'ils sont utiles, mais j'ai l'impression que l'ajustement n'est pas toujours le meilleur. Toute personnalisation est du côté learn. Jusqu'à présent, le package sparse n'a pas été optimisé pour cette application.


Je viens d'essayer des tests de produits matriciels en utilisant le sparse.random méthode pour créer une matrice clairsemée avec une parcimonie spécifiée. La multiplication matricielle clairsemée a donné de meilleurs résultats que prévu.

In [251]: M=sparse.random(1000,1000,.5)

In [252]: timeit M1=M*M
1 loops, best of 3: 2.78 s per loop

In [253]: timeit Ma=M.toarray(); M2=Ma.dot(Ma)
1 loops, best of 3: 4.28 s per loop

C'est un problème de taille; pour une matrice plus petite, le dot dense est plus rapide

In [255]: M=sparse.random(100,100,.5)

In [256]: timeit M1=M*M
100 loops, best of 3: 3.24 ms per loop

In [257]: timeit Ma=M.toarray(); M2=Ma.dot(Ma)
1000 loops, best of 3: 1.44 ms per loop

Mais comparez l'indexation

In [268]: timeit M.tocsr()[500,500]
10 loops, best of 3: 86.4 ms per loop

In [269]: timeit Ma[500,500]
1000000 loops, best of 3: 318 ns per loop

In [270]: timeit Ma=M.toarray();Ma[500,500]
10 loops, best of 3: 23.6 ms per loop
16
hpaulj

une matrice clairsemée est une matrice dans laquelle la plupart des éléments sont nuls Est-ce un moyen approprié de déterminer quand utiliser un format de matrice clairsemée - dès que> 50% des valeurs sont nulles? Ou est-il judicieux d'utiliser au cas où?

Il n'y a pas de règle générale. Cela dépend uniquement de votre utilisation exacte plus tard. Vous devez calculer la complexité du modèle sur la base d'une matrice clairsemée et sans, et ensuite vous pouvez trouver le "point idéal". Cela dépendra à la fois du nombre d'échantillons et de la dimension. En général, cela se résume souvent à des multiplications matricielles de la forme

X' W

où X est la matrice de données N xd, et W est une matrice de poids dx K. Par conséquent, la multiplication "dense" prend NdK temps, bien que clairsemée, en supposant que votre densité moyenne par ligne est p est NpdK. Ainsi, si votre parcimonie est de 50%, vous pouvez vous attendre à un fonctionnement presque 2x plus rapide. La partie la plus difficile est d'estimer les frais généraux de l'accès clairsemé par opposition à la base dense fortement optimisée.

Dans quelle mesure une matrice clairsemée améliore-t-elle les performances dans une tâche comme la mienne, en particulier par rapport à un tableau numpy ou à une liste standard?

Pour un cas particulier de LR, cela peut être même quelques fois plus rapide que le format dense, mais pour observer la différence, vous avez besoin de beaucoup de données (> 1000) de grande dimension (> 100).

Jusqu'à présent, je collecte mes données dans un tableau numpy, puis les convertis en csr_matrix dans Scipy. Est-ce la bonne façon de procéder? Je ne pouvais pas comprendre comment construire une matrice clairsemée à partir de zéro, et cela pourrait être impossible.

Non, ce n'est pas une bonne approche. Vous pouvez le construire "à partir de zéro" en construisant par exemple un dictionnaire puis en le convertissant etc. Il existe de nombreuses façons de construire une matrice clairsemée sans une matrice dense en premier lieu.

4
lejlot

@hpaulj Votre temps est erroné, vous obtenez des résultats lents en raison du mappage de sparse.random vers un tableau numpy (son lent) avec cela à l'esprit:

M=sparse.random(1000,1000,.5)
Ma=M.toarray()

%timeit -n 25 M1=M*M
352 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 25 loops each)

%timeit -n 25 M2=Ma.dot(Ma)
13.5 ms ± 2.17 ms per loop (mean ± std. dev. of 7 runs, 25 loops each)

Pour se rapprocher de numpy, nous devons avoir

M=sparse.random(1000,1000,.03)

%timeit -n 25 M1=M*M
10.7 ms ± 119 µs per loop (mean ± std. dev. of 7 runs, 25 loops each)

%timeit -n 25 M2=Ma.dot(Ma)
11.4 ms ± 564 µs per loop (mean ± std. dev. of 7 runs, 25 loops each)


1
komuher