在python中添加两个不同形状的`csc`稀疏矩阵

时间:2016-05-14 19:51:14

标签: python scipy sparse-matrix

所以我需要添加两个不同形状的csc矩阵。矩阵看起来像这样:

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)矩阵确实有共同的元素。基于它们的最终行和列ID,尽管它们具有不同的形状。

我想将两个矩阵一起添加,同时保留较大矩阵(current_flows)的形状,并使current_flows的值保持不变result_flows没有与current_flows匹配的行和列ID。因此,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

如果您想进一步澄清,请告诉我,谢谢!

2 个答案:

答案 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

使用@ Vadim的例子:

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

Vadim的两个选择

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__的{​​{1}}方法包含(如果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。这是kludgy,只能在原始形状的合理范围内工作。并且可能不会比y._shape = x.shape方法更快。 with_updatedokcsr更适合这种形状变化。]

如果csc不是other,则会dok

对于匹配形状,求和时间为

self.tocsc()+other

答案 1 :(得分: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]])