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]