Как я могу эффективно преобразовать scipy разреженную матрицу в sympy sparse matrix?
У меня есть матрица A со следующими свойствами.
<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
with 888344 stored elements in Compressed Sparse Column format>
A имеет это содержание.
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]])
Теперь я пытаюсь создать симпатичную разреженную матрицу из этой scipy разреженной матрицы.
from sympy.matrices import SparseMatrix
A = SparseMatrix(A)
Но я получаю это сообщение об ошибке.
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().
Я смущен, потому что в этой матрице нет логических записей.
Спасибо за любую помощь!
Ответы
Ошибка
Когда вы получаете сообщение об ошибке, которое не понимаете, потратьте немного времени на то, чтобы просмотреть трассировку. Или хотя бы покажите нам!
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().
Для полного понимания требуется прочитать sympy
код, но беглый взгляд показывает, что он пытается обрабатывать ваш ввод как «полную матрицу» и просматривает строки. Ошибка не является результатом выполнения вами логических операций с записями, а sympy
является логической проверкой вашей разреженной матрицы. Он пытается проверить, пуста ли строка (чтобы ее можно было пропустить).
SparseMatrix
документы могут быть не самыми ясными, но в большинстве примеров либо показан список точек, либо плоский массив ВСЕХ значений плюс форма, либо рваный список списков. Я подозреваю, что он пытается так относиться к вашей матрице, глядя на нее строка за строкой.
Но строка M
сама по себе является разреженной матрицей:
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>,
...]
И попытка проверить, пуста ли эта строка, not row
вызывает эту ошибку:
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().
Так что явно SparseMatrix
не может обрабатывать scipy.sparse
матрицу как есть (по крайней мере, не в формате csr
или csc
, и, вероятно, не в других. Плюс scipy.sparse
нигде не упоминается в SparseMatrix
документации!
из плотного массива
Преобразование разреженной матрицы в ее плотный эквивалент действительно работает:
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 ⎤
...⎦
Или список списков:
SparseMatrix(M.A.tolist())
из диктата
dok
Формат хранит разреженную матрицу в виде dict
, который затем может быть
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}
Что отлично работает в качестве ввода:
SparseMatrix(5,5,dict(M.todok()))
Я не знаю, что наиболее эффективно. Обычно при работе с sympy
нами (или, по крайней мере, я) не беспокоимся об эффективности. Достаточно просто заставить его работать. Эффективность более важна numpy/scipy
там, где массивы могут быть большими, и использование методов быстрой компиляции numpy имеет большое значение в скорости.
Наконец - так numpy
и sympy
не интегрированы. Это касается и разреженных версий. sympy
построен на Python, а не numpy
. Так что ввод в виде списков и dicts имеет наибольший смысл.
from sympy.matrices import SparseMatrix
import scipy.sparse as sps
A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))
С точки зрения человека, которому нравятся эффективные структуры памяти, это все равно что смотреть в бездну. Но это сработает.
Это упрощенная версия вашей ошибки.
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))
Итак, A
разреженная матрица с 6 элементами:
<3x3 sparse matrix of type '<class 'numpy.intc'>'
with 6 stored elements in Compressed Sparse Column format>
Его вызов SparseMatrix()
возвращает ошибку того же типа, что и у вас. Вы можете A
сначала преобразовать в массив numpy:
>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])