¿Cómo puedo convertir de manera eficiente una matriz dispersa scipy en una matriz dispersa sympy?
Tengo una matriz A con las siguientes propiedades.
<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
with 888344 stored elements in Compressed Sparse Column format>
A tiene este contenido.
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]])
Ahora estoy tratando de crear una matriz dispersa y simple a partir de esta matriz dispersa.
from sympy.matrices import SparseMatrix
A = SparseMatrix(A)
Pero recibo este mensaje de error.
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Estoy confundido porque esta matriz no tiene entradas lógicas.
¡Gracias por cualquier ayuda!
Respuestas
El error
Cuando reciba un error que no comprenda, tómese un poco de tiempo para ver el rastreo. ¡O al menos muéstranoslo!
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 comprensión completa requiere leer el sympy
código, pero una mirada superficial indica que está tratando de manejar su entrada como "matriz completa" y mira las filas. El error no es el resultado de que realice operaciones lógicas en las entradas, sino que sympy
está haciendo una prueba lógica en su matriz dispersa. Está tratando de verificar si la fila está vacía (para que pueda omitirla).
SparseMatrix
Es posible que los documentos no sean los más claros, pero la mayoría de los ejemplos muestran un dictado de puntos o una matriz plana de TODOS los valores más la forma, o una lista irregular de listas. Sospecho que está tratando de tratar su matriz de esa manera, mirándola fila por fila.
Pero la fila de M
es en sí misma una matriz dispersa:
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>,
...]
Y tratar de verificar si esa fila está vacía not row
produce este error:
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().
Claramente SparseMatrix
, no se puede manejar una scipy.sparse
matriz tal como está (al menos no en el formato csr
o csc
, y probablemente no en los demás. ¡Además, scipy.sparse
no se menciona en ninguna parte de los SparseMatrix
documentos!
de una matriz densa
La conversión de la matriz dispersa a su equivalente denso funciona:
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 una lista de listas:
SparseMatrix(M.A.tolist())
de dict
El dok
formato almacena una matriz dispersa como a dict
, que luego puede ser
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}
Que funciona bien como entrada:
SparseMatrix(5,5,dict(M.todok()))
No sé qué es lo más eficiente. Generalmente, cuando trabajamos con sympy
nosotros (o al menos yo) no nos preocupamos por la eficiencia. Solo haz que funcione es suficiente. La eficiencia es más relevante numpy/scipy
cuando las matrices pueden ser grandes, y el uso de métodos numéricos compilados rápidamente hace una gran diferencia en la velocidad.
Finalmente - numpy
y sympy
no están integrados. Eso se aplica también a las versiones dispersas. sympy
está construido en Python, no numpy
. Así que las entradas en forma de listas y dictados tienen más sentido.
from sympy.matrices import SparseMatrix
import scipy.sparse as sps
A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))
Desde la perspectiva de alguien a quien le gustan las estructuras de memoria eficientes, esto es como mirar al abismo. Pero funcionará.
Esta es una versión simplificada de su error.
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))
También lo A
es una matriz dispersa con 6 elementos:
<3x3 sparse matrix of type '<class 'numpy.intc'>'
with 6 stored elements in Compressed Sparse Column format>
Invocarlo SparseMatrix()
devuelve el mismo tipo de error que tiene. Es posible A
que desee convertir primero a una matriz numpy:
>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])