При определении матрицы с помощью coo
, или стиль воркуют ввода, (data,(row,col))
, дублированные записи суммируются. Создатели матриц жесткости (для pde-решений) часто используют это.
Это функция, которая использует это. Я преобразую матрицы в формат coo
(при необходимости), объединим их атрибуты и создаю новую матрицу.
def with_coo(x,y):
x=x.tocoo()
y=y.tocoo()
d = np.concatenate((x.data, y.data))
r = np.concatenate((x.row, y.row))
c = np.concatenate((x.col, y.col))
C = sparse.coo_matrix((d,(r,c)))
return C
С @ примеры Вадима:
In [59]: C_csc=current_flows.tocsc()
In [60]: R_csc=result_flows.tocsc()
In [61]: with_coo(C_csc, R_csc).tocsc().A
Out[61]:
array([[ 0, 0, 1],
[-1, 0, 4],
[ 0, -2, 0],
[ 3, 0, 0]], dtype=int32)
При создании таймингов мы должны быть осторожны, так как преобразование формата нетривиальность, например,
In [70]: timeit C_csc.tocoo()
10000 loops, best of 3: 128 µs per loop
In [71]: timeit C_csc.todok()
1000 loops, best of 3: 258 µs per loop
Вадима два варианта
def with_dok(x, y):
for k in y.keys(): # no has_key in py3
if k in x:
x[k] += y[k]
else:
x[k] = y[k]
return x
def with_update(x,y):
x.update((k, v+x.get(k)) for k, v in y.items())
return x
Начиная с форматом csc
:
In [74]: timeit with_coo(C_csc,R_csc).tocsc()
1000 loops, best of 3: 629 µs per loop
In [76]: timeit with_update(C_csc.todok(),R_csc.todok()).tocsc()
1000 loops, best of 3: 1 ms per loop
In [77]: timeit with_dok(C_csc.todok(),R_csc.todok()).tocsc()
1000 loops, best of 3: 1.12 ms per loop
Я предполагаю, что мой coo
подход будет масштабироваться лучше - но это только догадка на данный момент ,
Принимая конверсии с картинки, обновление dok
выглядит лучше. y
имеет только 2 предмета, и он не делает никаких копий - он напрямую изменяет x
.
In [78]: %%timeit x=C_csc.todok(); y=R_csc.todok()
....: with_update(x, y)
....:
10000 loops, best of 3: 33.6 µs per loop
In [79]: %%timeit x=C_csc.tocoo(); y=R_csc.tocoo()
with_coo(x, y)
....:
10000 loops, best of 3: 138 µs per loop
================
Метод __add__
для dok_matrix
содержит (если other
также dok
). Есть комментарий, интересующийся, нужно ли им проверять shape
.
new = dok_matrix(self.shape, dtype=res_dtype)
new.update(self)
for key in other.keys():
new[key] += other[key]
[Я могу обойти shape
проверки в x+y
, если я первый изменить форму y
, например, y._shape = x.shape
. Это kludgy и работает только в рациональных пределах оригинальных форм. И может быть не быстрее, чем подход with_update
. dok
больше поддаются такого рода изменения формы, чем csr
или csc
.]
Если other
не dok
, он делает self.tocsc()+other
.
Для сравнения формы, времена суммирования являются
In [91]: timeit current_flows+current_flows
1000 loops, best of 3: 413 µs per loop
In [92]: timeit C_csc+C_csc
1000 loops, best of 3: 223 µs per loop
Привет! Спасибо за ответ. Ваше решение похоже, что это может сработать, но знаете, как преобразовать мои существующие 'csc_matrix' в класс' dok'? –
В моих таймингах версия 'update' выполняется быстрее. В других вопросах SO я обнаружил, что словарь 'update' является самым быстрым способом изменения значений матрицы' dok'. Индексированный доступ к элементам 'dok' медленный по сравнению с обычным доступом к словарю. – hpaulj
@ Эрдель Эрл Используйте 'todok', например. 'current_flows = current_flows.todok()' @hpaulj Извините, мой плохой, вы правы. Я отредактировал свой ответ. –