2016-05-14 3 views
2

Итак, у меня есть две матрицы csc, которые мне нужно добавить вместе. Матрицы выглядеть следующим образом:Добавление двух `csc` разреженных матриц разных форм в python

current_flows = (7005, 1001) 50.0 
(8259, 1001) 65.0 
(14007, 1001) 45.0 
(9971, 1002) 80.0 
: : 
(69003, 211148) 0.0 

result_flows = (7005, 1001) 40 
(14007, 1001) 20 
(9971, 1002) 35 
: : 
(71136, 71137) 90 

final_flows = current_flows + result_flows 

Как проиллюстрировано некоторыми из строк и столбцов ID показал: (7005, 1001), (14007, 1001), (9971, 1002) матрицы имеет общие элементы. Исходя из их окончательных строк и идентификаторов столбцов, хотя они имеют разную форму.

Я хотел бы добавить две матрицы вместе, сохраняя при этом форму большей матрицы (current_flows) и сохранение значений current_flows то же самое, где result_flows не имеет строки и столбца, который соответствует ID current_flows. Так, final_flows будет иметь строк и столбцов индексов распространяется на: (69003, 211148), хотя result_flows распространяется только на (71136, 71137)

Таким образом, я хотел бы мой выход будет:

final_flows = (7005, 1001) 90.0 
(8259, 1001) 65.0 
(14007, 1001) 65.0 
(9971, 1002) 115.0 
: : 
(71136, 71137) 90 
(69003, 211148) 0.0 

Позвольте мне знать, если вы хотите какой-либо дальнейшее разъяснение, спасибо!

ответ

3

При определении матрицы с помощью 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 
1

Вы должны преобразовать матрицы в класс dok. Затем индексы и данные будут сохранены в виде словаря. Обратите внимание, что вторая матрица result_flows не должна иметь значений с индексами, превышающими current_flows. (Отредактировано, благодаря комментарию @hpaulj).

from scipy import sparse 

current_flows = sparse.dok_matrix([[0, 0, 1], 
            [2, 0, 4], 
            [0, 0, 0], 
            [3, 0, 0]] 
            ) 

result_flows = sparse.dok_matrix([[0, 0, 0, 0, 0], 
            [-3, 0, 0, 0, 0], 
            [0, -2, 0, 0, 0]] 
           ) 

current_flows.update((k, v + current_flows.get(k)) for k, v in result_flows.items()) 

current_flows.todense() 

Out[108]: matrix([[ 0, 0, 1], 
        [-1, 0, 4], 
        [ 0, -2, 0], 
        [ 3, 0, 0]]) 
+0

Привет! Спасибо за ответ. Ваше решение похоже, что это может сработать, но знаете, как преобразовать мои существующие 'csc_matrix' в класс' dok'? –

+1

В моих таймингах версия 'update' выполняется быстрее. В других вопросах SO я обнаружил, что словарь 'update' является самым быстрым способом изменения значений матрицы' dok'. Индексированный доступ к элементам 'dok' медленный по сравнению с обычным доступом к словарю. – hpaulj

+0

@ Эрдель Эрл Используйте 'todok', например. 'current_flows = current_flows.todok()' @hpaulj Извините, мой плохой, вы правы. Я отредактировал свой ответ. –

Смежные вопросы