Вопрос по sparse-matrix, row, scipy – scipy.sparse: установить строку в нули

8

Предположим, у меня есть матрица в формате CSR, каков наиболее эффективный способ установить строку (или строки) в нули?

Следующий код работает довольно медленно:

A = A.tolil()
A[indices, :] = 0
A = A.tocsr()

Я должен был преобразовать вscipy.sparse.lil_matrix потому что формат CSR, кажется, не поддерживает ни причудливую индексацию, ни установку значений для срезов.

Ну, я только что попробовал[A.__setitem__((i, j), 0) for i in indices for j in range(A.shape[1])] а такжеSciPy сказал мне, чтоSparseEfficiencyWarning: changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient.... Pierre GM
Понятия не имею, есть ли у scipy какая-либо поддержка, но поскольку это матрица CSR, это может быть эффективно обработано (по крайней мере, вручную). Один вопрос: хотите ли вы изменить шаблон разреженности, или эти 0 должны быть просто численно 0? seberg
Я не уверен, что подразумевается под шаблоном разреженности. Я перехожу к решению системы уравнений с помощью функции scipy.sparse.linalg.spsolve. Я надеюсь, что это устанавливает необходимость изменения модели разреженности или ее отсутствия. Ashwin Srinath
@AshwinSrinath Я отправил ответ, я думаю, вы, вероятно, не заботитесь об этом. Это могло быmaybe быть интересным, если вы взаимодействуете с решателем относительно низкого уровня, и это похоже на возвращение якобиана для каждой только что измененной итерации, тогда решатель может ожидать, что шаблон разреженности не изменится. Прочитайте статью в Википедии, но я думаю, что выshould изменить его (для экономии места и расчета). seberg

Ваш Ответ

3   ответа
6

Я думаю, что scipy просто не реализует это, но формат CSR вполне бы это поддержал, пожалуйста, прочитайте статью в Википедии на тему «Разреженная матрица». о чемindptrи т. д. являются:

# A.indptr is an array, one for each row (+1 for the nnz):

def csr_row_set_nz_to_val(csr, row, value=0):
    """Set all nonzero elements (elements currently in the sparsity pattern)
    to the given value. Useful to set to 0 mostly.
    """
    if not isinstance(csr, scipy.sparse.csr_matrix):
        raise ValueError('Matrix given must be of CSR format.')
    csr.data[csr.indptr[row]:csr.indptr[row+1]] = value

# Now you can just do:
for row in indices:
    csr_row_set_nz_to_val(A, row, 0)

# And to remove zeros from the sparsity pattern:
A.eliminate_zeros()

Конечно, это удаляет 0, которые были установлены из другого места сeliminate_zeros из разреженной картины. Если вы хотите сделать это (на данный момент), зависит от того, что вы делаете на самом деле, т.е. Исключение может иметь смысл откладывать до тех пор, пока не будут выполнены все другие вычисления, которые могут добавить новые нули, или в некоторых случаях у вас могут быть значения 0, которые вы захотите изменить позже, поэтому было бы очень плохо их исключать!

Вы можете в принципе, конечно, замкнутьeliminate_zeros а такжеprune, но это должно быть много хлопот, и может быть даже медленнее (потому что вы не будете делать это в C).


Details about eliminiate_zeros (and prune)

Разреженная матрица, как правило, не сохраняет нулевые элементы, а просто хранит там, где находятся ненулевые элементы (грубо и разными способами).eliminate_zeros удаляет все нули в вашей матрице из шаблона разреженности (т. е. для этой позиции не сохраняется значение, если до этогоwas vlaue хранится, но это было 0). Исключение плохо, если вы хотите изменить 0 на другое значение позже, в противном случае, это экономит место.

Prune просто сжимает массивы данных, хранящиеся, когда они длиннее, чем необходимо. Обратите внимание, что хотя я впервыеA.prune() там,A.eliminiate_zeros() уже включает чернослив.

Добавлено (надеюсь понятное) предложение. Обратите внимание, чтоprune() было ненужно,eliminate_zeros уже звонитprune
Спасибо! Это значительно ускорило ситуацию! Я просто хотел бы знать, что там делают операторы remove_zeros и prune? Ashwin Srinath
0

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

Вам понадобится одна из следующих функций:

import scipy.sparse

def zero_rows(M, rows):
    diag = scipy.sparse.eye(M.shape[0]).tolil()
    for r in rows:
        diag[r, r] = 0
    return diag.dot(M)

def zero_columns(M, columns):
    diag = scipy.sparse.eye(M.shape[1]).tolil()
    for c in columns:
        diag[c, c] = 0
    return M.dot(diag)

Пример использования:

>>> A = scipy.sparse.csr_matrix([[1,0,3,4], [5,6,0,8], [9,10,11,0]])
>>> A
<3x4 sparse matrix of type '<class 'numpy.int64'>'
        with 9 stored elements in Compressed Sparse Row format>
>>> A.toarray()
array([[ 1,  0,  3,  4],
       [ 5,  6,  0,  8],
       [ 9, 10, 11,  0]], dtype=int64)

>>> B = zero_rows(A, [1])
>>> B
<3x4 sparse matrix of type '<class 'numpy.float64'>'
        with 6 stored elements in Compressed Sparse Row format>
>>> B.toarray()
array([[  1.,   0.,   3.,   4.],
       [  0.,   0.,   0.,   0.],
       [  9.,  10.,  11.,   0.]])

>>> C = zero_columns(A, [1, 3])
>>> C
<3x4 sparse matrix of type '<class 'numpy.float64'>'
        with 5 stored elements in Compressed Sparse Row format>
>>> C.toarray()
array([[  1.,   0.,   3.,   0.],
       [  5.,   0.,   0.,   0.],
       [  9.,   0.,  11.,   0.]])
0

ю.

Похожие вопросы