#python #sparse-matrix
#питон #разреженная матрица
Вопрос:
допустим, у меня есть матрица смежности в формате csr:
row = np.array([0, 0, 1, 3, 2, 2,3,4,4]) col = np.array([0, 4, 2, 2, 3, 1,4,0,3]) data = np.array([1]*len(row)) X= sp.csr_matrix((data, (row, col)), shape=(5, 5)) print(X) (0, 0) 1 (0, 4) 1 (1, 2) 1 (2, 1) 1 (2, 3) 1 (3, 2) 1 (3, 4) 1 (4, 0) 1 (4, 3) 1 print(X.todense()) [[1 0 0 0 1] [0 0 1 0 0] [0 1 0 1 0] [0 0 1 0 1] [1 0 0 1 0]]
у меня есть список узлов, которые я хочу сохранить, скажем, узлы 1 и 2 keep = [1,2]
как бы я сохранил все индексы в X, которые находятся в списке «сохранить» ? Например, я хочу, чтобы в конечном итоге все индексы, строка или столбец которых есть в списке, сохранялись:
(1, 2) 1 (2, 1) 1 (2, 3) 1 (3, 2) 1
X[keep]
возвращает только строки 1,2:
print(X[keep].todense()) [[0 0 1 0 0] [0 1 0 1 0]]
но я вижу, что узел 2 взаимодействует с узлами 1 и узлами 3; поэтому я хочу вернуть матрицу смежности, которая отражает двунаправленные связи матрицы смежности подмножества:
[[0 0 1 0 0] [0 1 0 1 0] [0 0 1 0 0*]
0* представляет собой тот факт, что, поскольку меня интересует только узел 1 (взаимодействует только с узлом 2) и узел 2 (взаимодействует с узлами 1 и 3), то, несмотря на то, что в исходной матрице мы наблюдаем, что узел 3 взаимодействует с узлами 2 и 4, узел 4 не в списке, поэтому мы его игнорируем. Следовательно, я хочу в конечном итоге получить что-то вроде:
(1, 2) 1 (2, 1) 1 (2, 3) 1 (3, 2) 1
…Я понимаю, что после внесения изменений в этот вопрос, чтобы попытаться прояснить, что я пытаюсь сделать, это может быть не такое простое решение, но я все еще не уверен, как к нему подойти.
Ответ №1:
Ваши индексы хранятся в:
ix = X.nonzero()
Вы можете создать логическое значение для подмножества ваших индексов:
inkeep = np.isin(ix[0],keep) | np.isin(ix[1],keep)
Тогда получите что-то вроде этого:
np.array(ix)[:,inkeep].T array([[1, 2], [2, 1], [2, 3], [3, 2]], dtype=int32)
Однако, если вы хотите вернуть разреженную матрицу, содержащую пересечение того, что вы хотите, т. Е. строк 1,2 и столбцов 1,2, это будет что-то вроде:
X[1:3,1:3]
или:
X[keep,:][:,keep]
Комментарии:
1. как бы я сохранил его в виде разреженной матрицы csr? после этого я понял, что мой mwe не совсем точно отражает то, с чем я работаю, но, по сути, я пытаюсь получить подмножество исходной симметричной/двунаправленной матрицы смежности. итак, исходя из моей первоначальной смежности, я выбираю только несколько узлов; и в подмножестве я хочу, чтобы оно все еще было симметричным … если это имеет смысл?
2. к сожалению, это не так. итак, если вы уже знаете нужные строки, разве это не вопрос подстановки матрицы в соответствии с этим?
3. хм, я думаю, что меня смущает разреженная матрица.. обычно я с ними не работаю, но мой набор данных большой, поэтому мне дали мой набор данных в виде сжатого csr. я знаю строки, которые пытаюсь сохранить, поэтому я попробовал X[сохранить], но он не возвращает симметричную матрицу
4. просто хотел прокомментировать, что я отредактировал свой оригинальный пост, чтобы лучше представить симметричную разреженную матрицу. ваш ответ действительно отражает то, что я опубликовал, а именно « строка = np.массив([0, 0, 1, 2, 2, 2,3,3,4,5,6,6,7,7,8,8,8,9]) col = np.массив([0, 4, 3, 2, 3, 1,1,4,2,3,1,4,3,2,2,3,1,4]) данные = np.массив([1]*len(строка)) X= sp.csr_matrix((данные, (строка, столбец)), форма=(10, 5))«
5. хорошо, я думаю, что ваш отредактированный пост не отражает того, чего вы хотите. если это матрица смежности, и вам нужны выбранные индексы, то вам нужно извлечь те же строки и столбцы
Ответ №2:
Я не пытался понять, что вы пытаетесь сделать. Но некоторые сведения о разреженных матрицах могут быть в порядке.
Сначала из ваших данных давайте создадим coo
формат:
In [1]: from scipy import sparse as sp In [2]: row = np.array([0, 0, 1, 3, 2, 2,3,4,4]) ...: col = np.array([0, 4, 2, 2, 3, 1,4,0,3]) ...: data = np.array([1]*len(row)) ...: X= sp.coo_matrix((data, (row, col)), shape=(5, 5)) ...: In [3]: X Out[3]: lt;5x5 sparse matrix of type 'lt;class 'numpy.int64'gt;' with 9 stored elements in COOrdinate formatgt; In [4]: X.A Out[4]: array([[1, 0, 0, 0, 1], [0, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1], [1, 0, 0, 1, 0]]) In [5]: X.row,X.col Out[5]: (array([0, 0, 1, 3, 2, 2, 3, 4, 4], dtype=int32), array([0, 4, 2, 2, 3, 1, 4, 0, 3], dtype=int32))
В coo
, row,col,data
атрибуты похожи на то, что вы указали, на самом деле они могут быть теми же массивами (если не копией).
csr
Формат обрабатывается — сортируется и суммируется, если есть дубликаты. Строка/столбец были изменены, поэтому расположение не является очевидным.
In [6]: Xr = X.tocsr() In [7]: Xr.indptr Out[7]: array([0, 2, 3, 5, 7, 9], dtype=int32) In [8]: Xr.indices Out[8]: array([0, 4, 2, 1, 3, 2, 4, 0, 3], dtype=int32)
csr
реализует большую часть скудной математики. Он также реализует индексирование; coo не реализует индексирование. На самом деле в более общих случаях csr
индексация реализуется с помощью матричного умножения. Разреженные матрицы первоначально были разработаны для больших задач линейной алгебры, таких как конечно-разностный и конечно-элементный код. Я ничего с этим не делал scipy.sparse.csgraph
.
Там, где это возможно csr
, индексация пытается вести себя как соответствующая плотная индексация
In [9]: keep=[1,2] In [10]: Xr[keep] Out[10]: lt;2x5 sparse matrix of type 'lt;class 'numpy.int64'gt;' with 3 stored elements in Compressed Sparse Row formatgt; In [11]: Xr.A[keep] Out[11]: array([[0, 0, 1, 0, 0], [0, 1, 0, 1, 0]])
Это просто выбирает две строки из матрицы/массива.
nonzero
Метод X
(или Xr
) должен давать те же массивы, которые вы получаете из плотного массива. Опять же, это, по сути row/col
, атрибуты coo
.
In [14]: X.nonzero() Out[14]: (array([0, 0, 1, 3, 2, 2, 3, 4, 4], dtype=int32), array([0, 4, 2, 2, 3, 1, 4, 0, 3], dtype=int32)) In [15]: np.nonzero(X.A) Out[15]: (array([0, 0, 1, 2, 2, 3, 3, 4, 4]), array([0, 4, 2, 1, 3, 2, 4, 0, 3]))
Было бы лучше выяснить, что вы делаете с обычным массивом numpy, например X.A
. Как только это сработает, вы сможете напрямую работать с разреженными матрицами и их атрибутами.