Изменение диагонали или атрибута данных скудной разреженной матрицы также изменяет все копии этой матрицы - PullRequest
0 голосов
/ 24 июня 2019

У меня есть скудная разреженная матрица в одной variable, которую я копирую в другую новую variable.Если я теперь изменю диагональ разреженной матрицы в новом variable, то разреженная матрица в исходном variable также обновится.То же самое происходит, если я изменяю данные attribute.Я не понимаю, почему это так, есть ли причина такого поведения, которого я не вижу, или я делаю что-то непреднамеренно?

Что я хотел бы иметь, так это то, что я начинаюпокончив с разреженной матрицей, сделайте несколько ее копий и измените диагональ или все записи достаточным образом для этих копий.Но мои модификации влияют на все копии.

Я выяснил, что проблема не возникает, если я использую методы, которые создают копию разреженной матрицы, например power() или умножение матрицы на @.

Одна из модификаций, которую я хотел бы иметь, - это копия разреженной матрицы, в которой я беру абсолютное значение всех записей.Если я использую abs() непосредственно в разреженной матрице, он создает копию по желанию, и все в порядке.Но если я запишу абсолютные значения всех записей в данные attribute разреженной матрицы, это повлияет и на все остальные копии разреженной матрицы.Я обнаружил, что последний метод значительно быстрее, поэтому я предпочел бы использовать его.

Проблема не зависит от формата разреженной матрицы (кроме атрибута data для формата lil или dok).

Я попробовал это с Python 3.5.2 и Python 3.7.3 (два разных компьютера) в Spyder 3.3.1, и я использую scipy версию 1.3.0.

Скажем, у меня разреженная матрица

from scipy.sparse import csc_matrix as spmat
Msp = spmat(ar([[0.,-3.],[2.,-4.]]))

и я делаю несколько копий (я всегда могу скопировать Msp, без разницы)

M1 = Msp
M2 = M1

Если я сейчас сделаю

M2.data = abs(M2.data)

или

M1.setdiag([1,1])

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

Msp.toarray()
array([[1., 3.],
       [2., 1.]])

и то же самое для M1 и M2.

Я бы ожидал

M2.toarray()
array([[ 0., 3.],
       [ 2., 4.]])

и

M1.toarray()
array([[1., -3.],
       [2., 1.]])

и

Msp.toarray()
array([[ 0., -3.],
       [ 2., -4.]])

С другой стороны, если я сделаю что-то следующего типа

M2 = abs(M2)
M2 = M2.power(2)
M2 = M2@M2

он влияет только на M2 и оставляет M1 и Msp нетронутыми, как я и ожидал.

1 Ответ

1 голос
/ 24 июня 2019

Изменяя следующие строки:

M1 = Msp
M2 = M1

до:

M1 = Msp.copy()
M2 = M1.copy()

Ваш пример будет работать как задумано.

Массивы Numpy являются изменяемыми и, следовательно, изменения в объекте будут влиять на все переменные, которые ссылаются на этот объект.

Другими словами: При установке M2 = M1 M2 является только ссылкой на M1 и, следовательно, будет принимать значение M1 также в случае его изменения. M2 = M1.copy(), с другой стороны, передает копию M1 («значения») в M2, которая после этого не зависит от изменений в M1.

Причина, по которой примеры, приведенные в конце, влияют только на M2, заключается в том, что многие функции numpy возвращают новые массивы, которые не зависят от массивов, переданных в качестве параметров.

...