Bagaimana cara mengonversi matriks renggang scipy secara efisien menjadi matriks renggang sympy?

Aug 19 2020

Saya memiliki matriks A dengan properti berikut.

<1047x1047 sparse matrix of type '<class 'numpy.float64'>'
    with 888344 stored elements in Compressed Sparse Column format>

A memiliki konten ini.

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]])

Sekarang saya mencoba untuk membuat matriks renggang dari matriks renggang scipy.

from sympy.matrices import SparseMatrix
A = SparseMatrix(A)

Tapi saya mendapatkan pesan kesalahan ini.

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all().

Saya bingung karena matriks ini tidak memiliki entri logis.

Terima kasih atas bantuannya!

Jawaban

3 hpaulj Aug 19 2020 at 02:26

Kesalahan

Jika Anda mendapatkan kesalahan yang tidak Anda mengerti, luangkan sedikit waktu untuk melihat traceback. Atau setidaknya tunjukkan pada kami!

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().

Pemahaman penuh memerlukan pembacaan sympykode, tetapi tampilan sepintas menunjukkan bahwa ia mencoba menangani masukan Anda sebagai "matriks penuh", dan melihat baris. Kesalahan ini bukan akibat Anda melakukan operasi logika pada entri, tetapi itu sympyadalah melakukan uji logika pada matriks renggang Anda. Ini mencoba untuk memeriksa apakah baris tersebut kosong (sehingga dapat melewatinya).

SparseMatrixdocs mungkin bukan yang paling jelas, tetapi sebagian besar contoh menampilkan dikt poin, atau larik datar dari SEMUA nilai plus bentuk, atau daftar daftar yang tidak rata. Saya menduga itu mencoba memperlakukan matriks Anda seperti itu, melihatnya baris demi baris.

Tetapi baris Mitu sendiri merupakan matriks renggang:

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>,
...]

Dan mencoba untuk memeriksa apakah baris itu kosong not rowmenghasilkan kesalahan ini:

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().

Jadi jelas SparseMatrixtidak dapat menangani scipy.sparsematriks sebagaimana adanya (setidaknya tidak dalam format csratau csc, dan mungkin bukan yang lain. Plus scipy.sparsetidak disebutkan di mana pun di SparseMatrixdokumen!

dari larik padat

Mengonversi matriks renggang ke padanan padatnya dapat dilakukan:

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        ⎤
...⎦

Atau daftar daftar:

 SparseMatrix(M.A.tolist()) 

dari dict

The dokFormat menyimpan matriks jarang sebagai dict, yang kemudian dapat

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}

Yang berfungsi dengan baik sebagai masukan:

SparseMatrix(5,5,dict(M.todok()))

Saya tidak tahu mana yang paling efisien. Umumnya saat bekerja dengan sympykami (atau setidaknya saya) tidak khawatir tentang efisiensi. Cukup membuatnya bekerja sudah cukup. Efisiensi lebih relevan di numpy/scipymana array bisa berukuran besar, dan menggunakan metode numpy yang dikompilasi cepat membuat perbedaan besar dalam kecepatan.

Akhirnya - numpydan sympytidak terintegrasi. Itu berlaku juga untuk versi renggang. sympydibangun di atas Python, bukan numpy. Jadi masukan dalam bentuk daftar dan dicts paling masuk akal.

1 CJR Aug 19 2020 at 01:24
from sympy.matrices import SparseMatrix
import scipy.sparse as sps

A = sps.random(100, 10, format="dok")
B = SparseMatrix(100, 10, dict(A.items()))

Dari perspektif seseorang yang menyukai struktur memori yang efisien, ini seperti menatap ke dalam jurang. Tapi itu akan berhasil.

1 mathfux Aug 19 2020 at 02:12

Ini adalah versi sederhana dari kesalahan Anda.

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))

Begitu Ajuga matriks renggang dengan 6 elemen:

<3x3 sparse matrix of type '<class 'numpy.intc'>'
    with 6 stored elements in Compressed Sparse Column format>

Memanggilnya SparseMatrix()mengembalikan jenis kesalahan yang sama yang Anda miliki. Anda mungkin ingin mengonversi Ake array numpy terlebih dahulu:

>>> SparseMatrix(A.todense())
Matrix([
[1, 0, 2],
[0, 0, 3],
[4, 5, 6]])