Как рассчитать диагональную матрицу степени из огромной (scipy.sparse) матрицы?

Учитывая квадратичную матрицу размерности 1 миллион, я хочу вычислить диагональную матрицу степени.

Матрица диагональных степеней определяется как диагональная матрица, в которой количество ненулевых значений в строке является элементами.

Матрица, назовем ее A, имеет формат scipy.sparse.csr_matrix.

Если бы у моей машины было достаточно мощности, я бы просто сделал

diagonal_degrees = []
for row in A:
    diagonal_degrees.append(numpy.sum(row!=0))

Я даже пробовал это, но это приводит к

ValueError: array is too big.

Поэтому я попытался использовать разреженную структуру scipy. Я думал об этом так:

diagonal_degrees = []
CSC_format = A.tocsc() # A is in scipys CSR format.
for i in range(CSC_format.shape[0]):
    row = CSC_format.getrow(i)
    diagonal_degrees.append(numpy.sum(row!=0))

У меня есть два вопроса:

  1. Есть ли более эффективный способ, я, возможно, упустил из виду?
  2. В то время как документы разреженного состояния scipy:

Все преобразования между форматами CSR, CSC и COO являются эффективными операциями с линейным временем.

Почему я получаю

SparseEfficiencyWarning: changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.

при переходе с CSR на CSC?


person Aufwind    schedule 18.01.2012    source источник
comment
Вы получаете сообщение об ошибке, когда устанавливаете элемент в файле csr_matrix. Изменение структуры разреженности не имеет ничего общего с преобразованием между различными форматами разреженных матриц. Это когда вы добавляете плотный предмет(ы).   -  person Joe Kington    schedule 18.01.2012
comment
Если все, что вам нужно сделать, это подсчитать ненулевые элементы, nonzero выглядит многообещающе.   -  person Avaris    schedule 18.01.2012
comment
Как уже указал вам @avaris, вы можете просто сделать diag_deg, _ = np.histogram(x.nonzero()[0], np.arange(x.shape[0]+1))   -  person Joe Kington    schedule 18.01.2012
comment
@Joe: Пожалуйста, превратите это в ответ, чтобы я мог проголосовать и принять.   -  person Aufwind    schedule 18.01.2012
comment
На мой взгляд, это действительно должен быть @Avaris, поскольку именно он указал на nonzero.   -  person Joe Kington    schedule 18.01.2012
comment
Кто из вас, двух добрых людей, хочет получить очки, тот их получит. :-)   -  person Aufwind    schedule 18.01.2012
comment
Ну, для меня это не имеет большого значения, но чтобы оставить этот вопрос в покое, я сделаю на него ответ :).   -  person Avaris    schedule 18.01.2012


Ответы (1)


Если все, что вам нужно, это подсчитать ненулевые элементы, есть nonzero, который может быть полезен.

Точный код будет (с помощью Joe Kington и matehat):

diag_deg, _ = np.histogram(x.nonzero()[0], np.arange(x.shape[0]+1))

# generating a diagonal matrix with diag_deg
dim = x.shape[0]
diag_mat = np.zeros((dim**2, ))
diag_mat[np.arange(0, dim**2, dim+1)] = diag_deg
diag_mat.reshape((dim, dim))

Хотя для больших массивов (dim ~ 1 million), как отмечает Aufwind, np.zeros((dim**2, )) дает исключение: ValueError: Maximum allowed dimension exceeded. Альтернативным обходным путем является использование разреженных матриц:

diag_mat = sparse.coo_matrix((dim, dim))
diag_mat.setdiag(diag_deg)
person Avaris    schedule 18.01.2012
comment
Просто чтобы добавить к отличному решению, если кто-то хочет сгенерировать диагональную матрицу из diag_deg, он может написать diag_mat = np.zeros((x.shape[0]**2, )), затем diag_mat[np.arange(0, x.shape[0]**2, x.shape[0]+1)] = diag_deg и, наконец, diag_mat.reshape((x.shape[0], x.shape[0])). Извините за скудный код… Я не хотел создавать для этого новый ответ;) - person matehat; 18.01.2012
comment
@matehat: Спасибо за завершение решения. Пусть dim = x.shape[0] К сожалению, np.zeros((dim**2,)) приводит к ValueError: Maximum allowed dimension exceeded, когда dim слишком велико. В моем случае dim составляет около миллиона. Поэтому при работе с матрицами большой размерности следует выбирать другой путь. Например: diag_mat = sparse.coo_matrix((dim,dim)), а затем diag_mat.setdiag(diag_deg). - person Aufwind; 04.02.2012
comment
@Avaris: Возможно, вы хотите объединить эти два комментария в свой ответ. Таким образом, он становится более полным и лучше читаемым для людей, столкнувшихся с похожей проблемой. - person Aufwind; 04.02.2012
comment
@Aufwind: Подойдет. Спасибо за уведомление. - person Avaris; 04.02.2012