2 votes

Scipy : suppression conditionnelle des colonnes d'une matrice éparse

J'ai une grande matrice csr éparse (79 000 x 480 000). J'essaie de supprimer toutes les colonnes (dans un certain intervalle) pour lesquelles chaque valeur < k.

Dans les matrices numpy ordinaires, cela se fait simplement par un masque :

m = np.array([[0,2,1,1],
                [0,4,2,0],
                [0,3,4,0]])
mask = (arr < 2)
idx = mask.all(axis=0)
result = m[:, ~idx]
print result
>>> [[2 1]
     [4 2]
     [3 4]]

L'opérateur unaire de négation bit à bit ~ et la fonctionnalité de masque booléen ne sont toutefois pas disponibles pour les matrices peu denses. Quelle est la meilleure méthode pour :

  1. Obtenir les indices des colonnes dont toutes les valeurs remplissent la condition e < k.
  2. Supprimer ces colonnes en fonction de la liste des indices.

Quelques points à noter :

  1. Les colonnes représentent les caractéristiques des textes ngrammes : il n'y a pas de colonnes dans la matrice dont chaque élément est égal à zéro.

L'utilisation du format matriciel csr est-elle un choix plausible pour cela ? Est-ce que je transpose et utilise .nonzero() ? Je dispose d'une bonne quantité de mémoire de travail (192 Go), de sorte que l'efficacité en termes de temps est préférable à l'efficacité en termes de mémoire.

4voto

hpaulj Points 6132

Si je le fais

M = sparse.csr_matrix(m)

M < 2

J'obtiens un avertissement d'efficacité ; toutes les valeurs 0 de M satisfont à la condition,

In [1754]: print(M)
  (0, 1)    2
  (0, 2)    1
  (0, 3)    1
  (1, 1)    4
  (1, 2)    2
  (2, 1)    3
  (2, 2)    4
In [1755]: print(M<2)
/usr/lib/python3/dist-packages/scipy/sparse/compressed.py:275: SparseEfficiencyWarning: Comparing a sparse matrix with a scalar greater than zero using < is inefficient, try using >= instead.
  warn(bad_scalar_msg, SparseEfficiencyWarning)
  (0, 0)    True     # not in M
  (0, 2)    True
  (0, 3)    True
  (1, 0)    True    # not in M
  (1, 3)    True
  (2, 0)    True    # not in M
  (2, 3)    True
In [1756]: print(M>=2)   # all a subset of M
  (0, 1)    True
  (1, 1)    True
  (1, 2)    True
  (2, 1)    True
  (2, 2)    True

Si I=M>=2 ; il n'y a pas de all mais il existe une méthode sum .

In [1760]: I.sum(axis=0)
Out[1760]: matrix([[0, 3, 2, 0]], dtype=int32)

sum est en fait réalisée à l'aide d'une multiplication matricielle

In [1769]: np.ones((1,3),int)*I
Out[1769]: array([[0, 3, 2, 0]], dtype=int32)

Utilisation nonzero pour trouver les colonnes non nulles :

In [1778]: np.nonzero(I.sum(axis=0))
Out[1778]: (array([0, 0], dtype=int32), array([1, 2], dtype=int32))
In [1779]: M[:,np.nonzero(I.sum(axis=0))[1]]
Out[1779]: 
<3x2 sparse matrix of type '<class 'numpy.int32'>'
    with 6 stored elements in Compressed Sparse Row format>
In [1780]: M[:,np.nonzero(I.sum(axis=0))[1]].A
Out[1780]: 
array([[2, 1],
       [4, 2],
       [3, 4]], dtype=int32)

Points généraux :

  • attention aux valeurs 0 lors des comparaisons

  • attention aux fausses valeurs lorsque l'on fait de la logique sur des matrices peu denses

  • les matrices peu denses sont optimisées pour les mathématiques, en particulier la multiplication des matrices

  • l'indexation éparse n'est pas aussi puissante que l'indexation par tableau ; elle n'est pas non plus aussi rapide.

  • noter quand les opérations produisent une matrice dense

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X