Come posso convertire in modo efficiente una matrice sparsa scipy in una matrice sparsa sympy?
Ho una matrice A con le seguenti proprietà.
<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
with 888344 stored elements in Compressed Sparse Column format>
A ha questo contenuto.
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]])
Ora sto cercando di creare una matrice sparsa sympy da questa matrice sparsa scipy.
from sympy.matrices import SparseMatrix
A = SparseMatrix(A)
Ma ricevo questo messaggio di errore.
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Sono confuso perché questa matrice non ha voci logiche.
Grazie per qualsiasi aiuto!
Risposte
L'errore
Quando ricevi un errore che non capisci, dedica un po 'di tempo a guardare il traceback. O almeno mostracelo!
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().
Una piena comprensione richiede la lettura del sympy
codice, ma uno sguardo superficiale indica che sta cercando di gestire l'input come "matrice completa" e guarda le righe. L'errore non è il risultato dell'esecuzione di operazioni logiche sulle voci, ma di sympy
un test logico sulla matrice sparsa. Sta cercando di controllare se la riga è vuota (quindi può saltarla).
SparseMatrix
docs potrebbe non essere il più chiaro, ma la maggior parte degli esempi mostra un dettato di punti o un array piatto di TUTTI i valori più la forma o un elenco irregolare di elenchi. Sospetto che stia cercando di trattare la tua matrice in quel modo, guardandola riga per riga.
Ma la riga di M
è essa stessa una matrice sparsa:
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>,
...]
E provare a verificare se quella riga è vuota not row
produce questo errore:
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().
Quindi chiaramente SparseMatrix
non può gestire una scipy.sparse
matrice così com'è (almeno non nel formato csr
o csc
, e probabilmente non negli altri. Inoltre scipy.sparse
non è menzionato da nessuna parte nei SparseMatrix
documenti!
dalla matrice densa
La conversione della matrice sparsa nel suo equivalente denso funziona:
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 ⎤
...⎦
O un elenco di elenchi:
SparseMatrix(M.A.tolist())
da dict
Il dok
formato memorizza una matrice sparsa come un dict
, che quindi può essere
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}
Che funziona bene come input:
SparseMatrix(5,5,dict(M.todok()))
Non so cosa sia più efficiente. Generalmente quando si lavora con sympy
noi (o almeno io) non ci si preoccupa dell'efficienza. Basta farlo funzionare è sufficiente. L'efficienza è più rilevante numpy/scipy
quando gli array possono essere grandi e l'uso dei metodi numpy compilati velocemente fa una grande differenza in termini di velocità.
Infine - numpy
e sympy
non sono integrati. Ciò vale anche per le versioni sparse. sympy
è costruito su Python, non numpy
. Quindi gli input sotto forma di elenchi e dettami hanno più senso.
from sympy.matrices import SparseMatrix
import scipy.sparse as sps
A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))
Dal punto di vista di qualcuno a cui piacciono le strutture di memoria efficienti, è come guardare nell'abisso. Ma funzionerà.
Questa è una versione semplificata del tuo errore.
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))
Quindi A
è una matrice sparsa con 6 elementi:
<3x3 sparse matrix of type '<class 'numpy.intc'>'
with 6 stored elements in Compressed Sparse Column format>
Richiamarlo SparseMatrix()
restituisce lo stesso tipo di errore che hai. Potresti prima convertire A
in array numpy:
>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])