Comment puis-je convertir efficacement une matrice scipy sparse en une matrice sympy sparse?
J'ai une matrice A avec les propriétés suivantes.
<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
with 888344 stored elements in Compressed Sparse Column format>
A a ce contenu.
array([[ 1.00000000e+00, -5.85786642e-17, -3.97082034e-17, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[ 6.82195979e-17, 1.00000000e+00, -4.11166786e-17, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-4.98202332e-17, 1.13957868e-17, 1.00000000e+00, ...,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00],
...,
[ 4.56847824e-15, 1.32261454e-14, -7.22890998e-15, ...,
1.00000000e+00, 0.00000000e+00, 0.00000000e+00],
[-9.11597396e-15, -2.28796167e-14, 1.26624823e-14, ...,
0.00000000e+00, 1.00000000e+00, 0.00000000e+00],
[ 1.80765584e-14, 1.93779820e-14, -1.36520100e-14, ...,
0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
J'essaye maintenant de créer une matrice clairsemée sympy à partir de cette matrice clairsemée scipy.
from sympy.matrices import SparseMatrix
A = SparseMatrix(A)
Mais j'obtiens ce message d'erreur.
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Je suis confus car cette matrice n'a pas d'entrées logiques.
Merci pour toute aide!
Réponses
L'erreur
Lorsque vous obtenez une erreur que vous ne comprenez pas, prenez un peu de temps pour examiner la trace. Ou du moins nous le montrer!
In [288]: M = sparse.random(5,5,.2, 'csr')
In [289]: M
Out[289]:
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 5 stored elements in Compressed Sparse Row format>
In [290]: print(M)
(1, 1) 0.17737340878962138
(2, 2) 0.12362174819457106
(2, 3) 0.24324155883057885
(3, 0) 0.7666429046432961
(3, 4) 0.21848551209470246
In [291]: SparseMatrix(M)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-291-cca56ea35868> in <module>
----> 1 SparseMatrix(M)
/usr/local/lib/python3.6/dist-packages/sympy/matrices/sparse.py in __new__(cls, *args, **kwargs)
206 else:
207 # handle full matrix forms with _handle_creation_inputs
--> 208 r, c, _list = Matrix._handle_creation_inputs(*args)
209 self.rows = r
210 self.cols = c
/usr/local/lib/python3.6/dist-packages/sympy/matrices/matrices.py in _handle_creation_inputs(cls, *args, **kwargs)
1070 if 0 in row.shape:
1071 continue
-> 1072 elif not row:
1073 continue
1074
/usr/local/lib/python3.6/dist-packages/scipy/sparse/base.py in __bool__(self)
281 return self.nnz != 0
282 else:
--> 283 raise ValueError("The truth value of an array with more than one "
284 "element is ambiguous. Use a.any() or a.all().")
285 __nonzero__ = __bool__
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Une compréhension complète nécessite la lecture du sympy
code, mais un coup d'œil rapide indique qu'il essaie de gérer votre entrée comme une «matrice complète» et examine les lignes. L'erreur n'est pas le résultat de l'exécution d'opérations logiques sur les entrées, mais d' sympy
un test logique sur votre matrice creuse. Il essaie de vérifier si la ligne est vide (afin de pouvoir l'ignorer).
SparseMatrix
Les documents ne sont peut-être pas les plus clairs, mais la plupart des exemples montrent soit un dict de points, soit un tableau plat de TOUTES les valeurs plus la forme, soit une liste irrégulière de listes. Je soupçonne qu'il essaie de traiter votre matrice de cette façon, en la regardant ligne par ligne.
Mais la rangée de M
est elle-même une matrice clairsemée:
In [295]: [row for row in M]
Out[295]:
[<1x5 sparse matrix of type '<class 'numpy.float64'>'
with 0 stored elements in Compressed Sparse Row format>,
<1x5 sparse matrix of type '<class 'numpy.float64'>'
with 1 stored elements in Compressed Sparse Row format>,
...]
Et essayer de vérifier si cette ligne est vide not row
produit cette erreur:
In [296]: not [row for row in M][0]
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Il est donc clair que SparseMatrix
je ne peux pas gérer une scipy.sparse
matrice telle quelle (du moins pas au format csr
ou csc
, et probablement pas les autres. Plus scipy.sparse
n'est mentionné nulle part dans la SparseMatrix
documentation!
à partir d'un tableau dense
La conversion de la matrice clairsemée en son équivalent dense fonctionne:
In [297]: M.A
Out[297]:
array([[0. , 0. , 0. , 0. , 0. ],
[0. , 0.17737341, 0. , 0. , 0. ],
[0. , 0. , 0.12362175, 0.24324156, 0. ],
[0.7666429 , 0. , 0. , 0. , 0.21848551],
[0. , 0. , 0. , 0. , 0. ]])
In [298]: SparseMatrix(M.A)
Out[298]:
⎡ 0 0 0 0 0 ⎤
...⎦
Ou une liste de listes:
SparseMatrix(M.A.tolist())
de dict
Le dok
format stocke une matrice creuse sous forme de a dict
, qui peut alors être
In [305]: dict(M.todok())
Out[305]:
{(3, 0): 0.7666429046432961,
(1, 1): 0.17737340878962138,
(2, 2): 0.12362174819457106,
(2, 3): 0.24324155883057885,
(3, 4): 0.21848551209470246}
Ce qui fonctionne très bien comme entrée:
SparseMatrix(5,5,dict(M.todok()))
Je ne sais pas ce qui est le plus efficace. En général, lorsque vous travaillez avec sympy
nous (ou du moins moi), ne vous inquiétez pas de l'efficacité. Le faire fonctionner suffit. L'efficacité est plus pertinente numpy/scipy
là où les tableaux peuvent être volumineux, et l'utilisation des méthodes numpy compilées rapidement fait une grande différence en termes de vitesse.
Enfin - numpy
et sympy
ne sont pas intégrés. Cela vaut également pour les versions clairsemées. sympy
est construit sur Python, pas numpy
. Ainsi, les entrées sous forme de listes et de dictionnaires ont plus de sens.
from sympy.matrices import SparseMatrix
import scipy.sparse as sps
A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))
Du point de vue de quelqu'un qui aime les structures de mémoire efficaces, c'est comme regarder dans l'abîme. Mais cela fonctionnera.
Ceci est une version simplifiée de votre erreur.
from scipy import sparse
row = np.array([0, 0, 1, 2, 2, 2])
col = np.array([0, 2, 2, 0, 1, 2])
data = np.array([1, 2, 3, 4, 5, 6])
A = sparse.csc_matrix((data, (row, col)), shape=(3, 3))
Ainsi A
est une matrice clairsemée avec 6 éléments:
<3x3 sparse matrix of type '<class 'numpy.intc'>'
with 6 stored elements in Compressed Sparse Column format>
L'appeler SparseMatrix()
renvoie le même type d'erreur que vous. Vous voudrez peut-être d'abord convertir A
en tableau numpy:
>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])