Разреженные матрицы Python-Scipy - что делает A [i, j]? - PullRequest
0 голосов
/ 18 мая 2019

Согласно моему предыдущему вопросу здесь ( Python - Умножение разреженной строки матрицы с не разреженным вектором на индекс ) прямая индексация разреженных матриц невозможна (по крайней мере, если вы не хотите работатьс тремя массивами, по которым определяется матрица sparse.csr, data, indices, indptr).Но я только что узнал, что при наличии csr-разреженной матрицы A эта операция работает нормально и дает правильные результаты: A[i, j].Что я также заметил: это ужасно медленно, даже медленнее, чем работа с плотными матрицами.

Я не смог найти никакой информации об этом методе индексации, поэтому мне интересно: что именно делает A[i, j]?

Если вы хотите, чтобы я сделал предположение, я бы сказал, что он производит плотную матрицу, а затем индексирует ее, как обычно.

1 Ответ

1 голос
/ 18 мая 2019
In [211]: M = sparse.csr_matrix(np.eye(3))                                   
In [212]: M                                                                  
Out[212]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
    with 3 stored elements in Compressed Sparse Row format>

Индексирование с помощью [0] создает новую разреженную матрицу (1,3) формы:

In [213]: M[0]                                                               
Out[213]: 
<1x3 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in Compressed Sparse Row format>

Попытка индексации, которая снова дает другую разреженную матрицу или ошибку. Это потому, что это все еще форма 2d объекта (1,3).

In [214]: M[0][1]                                                            
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-214-0661a1f27e52> in <module>
----> 1 M[0][1]

/usr/local/lib/python3.6/dist-packages/scipy/sparse/csr.py in __getitem__(self, key)
    290             # [i, 1:2]
    291             elif isinstance(col, slice):
--> 292                 return self._get_row_slice(row, col)
    293             # [i, [1, 2]]
    294             elif issequence(col):

/usr/local/lib/python3.6/dist-packages/scipy/sparse/csr.py in _get_row_slice(self, i, cslice)
    397 
    398         if i < 0 or i >= M:
--> 399             raise IndexError('index (%d) out of range' % i)
    400 
    401         start, stop, stride = cslice.indices(N)

IndexError: index (1) out of range

Индексирование с помощью синтаксиса [0,1] работает, при этом два числа применяются к двум различным измерениям:

In [215]: M[0,1]                                                             
Out[215]: 0.0

A[0][1] работает с np.ndarray, но это потому, что первый [0] создает массив с на 1 меньше измерения. Но np.matrix и sparse возвращают 2d матрицу, а не 1d. Это одна из причин, по которой мы не рекомендуем np.matrix. С sparse матричная природа идет глубже, поэтому мы не можем просто ограничить ее.

Мы можем получить представление о коде, который используется для выбора элемента из разреженной матрицы, вызвав ошибку:

In [216]: M[0,4]                                                             
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-216-4919ae565782> in <module>
----> 1 M[0,4]

/usr/local/lib/python3.6/dist-packages/scipy/sparse/csr.py in __getitem__(self, key)
    287             # [i, j]
    288             if isintlike(col):
--> 289                 return self._get_single_element(row, col)
    290             # [i, 1:2]
    291             elif isinstance(col, slice):

/usr/local/lib/python3.6/dist-packages/scipy/sparse/compressed.py in _get_single_element(self, row, col)
    868         if not (0 <= row < M) or not (0 <= col < N):
    869             raise IndexError("index out of bounds: 0<=%d<%d, 0<=%d<%d" %
--> 870                              (row, M, col, N))
    871 
    872         major_index, minor_index = self._swap((row, col))

IndexError: index out of bounds: 0<=0<3, 0<=4<3

===

Да, индексирование элемента в разреженной матрице выполняется медленнее, чем индексирование в плотном массиве. Это не потому, что сначала он превращается в плотный. При индексировании плотного массива элемент просто требует преобразования n-d-индекса в плоский и выбора необходимых байтов в 1d-буфере плоских данных - и большая часть этого выполняется в быстро скомпилированном коде. Но, как вы можете видеть из трассировки, выбор элемента из разреженной матрицы более сложен, и во многом это Python.

Разреженный lil формат предназначен для ускорения индексации (и особенно для настройки). Но даже это немного медленнее, чем индексирование плотного массива. Не используйте разреженные матрицы, если вам нужно выполнить итерацию или иным образом повторно обращаться к отдельным элементам.

===

Чтобы дать представление о том, что связано с индексированием M, посмотрите на его ключевые атрибуты:

In [224]: M.data,M.indices,M.indptr                                          
Out[224]: 
(array([1., 1., 1.]),
 array([0, 1, 2], dtype=int32),
 array([0, 1, 2, 3], dtype=int32))

Чтобы выбрать строку 0, мы должны использовать indptr, чтобы выбрать срез из других:

In [225]: slc = slice(M.indptr[0],M.indptr[1])                               
In [226]: M.data[slc], M.indices[slc]                                        
Out[226]: (array([1.]), array([0], dtype=int32))

затем, чтобы выбрать столбец 1, мы должны проверить, находятся ли эти значения в indices[slc]. Если это так, верните соответствующий элемент в data[slc]. Если нет, верните 0.

Для более сложной индексации sparse фактически использует матричное умножение, создав матрицу extractor из индексов. Он также использует умножение для выполнения сумм строк или столбцов.

Матричное умножение - это слабая матричная сила - при условии, что матрица достаточно разреженная. Математические корни разреженных форматов, особенно csr, находятся в разреженных задачах линейных уравнений, таких как конечно-разностные и конечно-элементные PDES. * * === тысяча сорок-девять

Вот основные атрибуты lil матрицы

In [227]: ml=M.tolil()                                                       
In [228]: ml.data                                                            
Out[228]: array([list([1.0]), list([1.0]), list([1.0])], dtype=object)
In [229]: ml.rows                                                            
Out[229]: array([list([0]), list([1]), list([2])], dtype=object)
In [230]: ml.data[0],ml.rows[0]                                              
Out[230]: ([1.0], [0])          # cf Out[226]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...