使用`coo`矩阵和python中的numpy数组加速for循环的操作

时间:2016-05-17 09:07:21

标签: python arrays matrix scipy

我有一个numpy数组和一个coo矩阵。我需要根据coo矩阵中的元素更新numpy数组。 numpy数组和矩阵都非常大,这是它们的样子:

 graph_array = [[  1.0   1.0   5.0  9.0]
 [  2.0   5.0   6.0   5.0]
 [  3.0   5.0   7.0   6.0]]

matrix_coo = (1, 5) 0.5
(2, 8)  0.4
(5, 7)  0.8

我需要做的事情如下:

如果数组中每个列表中的第二个和第三个元素,即list_graph[i][1][2](可能是1,55,65,7)等于行和列在coo矩阵中配对,例如(1, 5), (2, 8) or (5, 7),那么与该对相关联的值(对于(1, 5)等于0.5)必须替换数组中列表中的第四个元素。

我的预期输出因此是:

output_array = [[  1.0   1.0   5.0  0.5]
[  2.0   5.0   6.0   5.0]
[  3.0   5.0   7.0   0.8]]

我目前使用的代码如下:

 row_idx = list(matrix_coo.row)
 col_idx = list(matrix_coo.col)
 data_idx = list(matrix_coo.data)

x = 0
    while x < len(row_cost_idx):
        for m in graph_array:
            if m[1] == row_idx[x]:
                if m[2] == col_idx[x]:
                    m[3] = data_idx[x]
        x += 1

它确实给了我正确的输出,但因为数组有21596个项目,矩阵有21596行,所以需要很长时间。

有更快的方法吗?

1 个答案:

答案 0 :(得分:1)

您的迭代是一个纯Python列表操作。 void MyClass::requestFinished(QNetworkReply*)作为row_idx的属性发起的事实不适用

可以通过以下方式清理它:

什么是coo_matrix?如果它与我们可以做的row_cost_idx相同

row_idx

我认为迭代是一样的,但还没有测试过。我也不确定速度。

for r,c,d in zip(matrix_coo.row, matrix_coo.col, matrix_coo.data): for m in graph_array: # not list_graph? if m[:2]==[r,c]: m[3] = d 的非零元素和matrix_coo的子列表的双重迭代必然会很慢,只是因为你进行了很多迭代。

如果graph_arraygraph_array numpy,我们可以一次测试所有行,例如

array

其中mask = (graph_array[:, :2]==[r,c]).all(axis=1) graph_array[mask,3] = d 对于具有正确索引的mask行具有1。 (再次未经测试)

为了获得更高的速度,我将graph_arraygraph_array同时转换为2d numpy(密集)数组,看看我是否可以通过一些数组操作解决问题。这些见解可能有助于我替换matrix_coo次迭代。

=========================

经过测试的代码

matrix_coo

运行

import numpy as np
from scipy import sparse

graph_array = np.array([[  1.0,   1.0,   5.0 , 9.0],
 [  2.0,   5.0 ,  6.0  , 5.0],
 [  3.0  , 5.0 ,  7.0 ,  6.0]])

r,c,d = [1,2,5], [5,8,7],[0.5,0.4,0.8]
matrix_coo = sparse.coo_matrix((d,(r,c)))

def org(graph_array, matrix_coo):
    row_idx = list(matrix_coo.row)
    col_idx = list(matrix_coo.col)
    data_idx = list(matrix_coo.data)

    x = 0
    while x < len(row_idx):
        for m in graph_array:
            if m[1] == row_idx[x]:
                if m[2] == col_idx[x]:
                    m[3] = data_idx[x]
        x += 1
    return graph_array

new_array = org(graph_array.copy(), matrix_coo)    
print(graph_array)
print(new_array)

def alt(graph_array, matrix_coo):
    for r,c,d in zip(matrix_coo.row, matrix_coo.col, matrix_coo.data):
        for m in graph_array: 
            if (m[[1,2]]==[r,c]).all():  # array test
                m[3] = d
    return graph_array

new_array = alt(graph_array.copy(), matrix_coo)    
print(new_array)

def altlist(graph_array, matrix_coo):
    for r,c,d in zip(matrix_coo.row, matrix_coo.col, matrix_coo.data):
        for m in graph_array:
            if (m[1:3]==[r,c]):   # list test
                m[3] = d
    return graph_array

new_array = altlist(graph_array.tolist(), matrix_coo)    
print(new_array)

def altarr(graph_array, matrix_coo):
    for r,c,d in zip(matrix_coo.row, matrix_coo.col, matrix_coo.data):
        mask = (graph_array[:, 1:3]==[r,c]).all(axis=1)
        graph_array[mask,3] = d
    return graph_array

new_array = alt(graph_array.copy(), matrix_coo)    
print(new_array)

对于这个小例子,你的功能最快。它也适用于列表和数组。对于小东西列表操作通常比阵列操作更快。因此,使用数组运算来比较2个数字并不是一种改进。

复制0909:~/mypy$ python3 stack3727173.py [[ 1. 1. 5. 9.] [ 2. 5. 6. 5.] [ 3. 5. 7. 6.]] [[ 1. 1. 5. 0.5] [ 2. 5. 6. 5. ] [ 3. 5. 7. 0.8]] [[ 1. 1. 5. 0.5] [ 2. 5. 6. 5. ] [ 3. 5. 7. 0.8]] [[1.0, 1.0, 5.0, 0.5], [2.0, 5.0, 6.0, 5.0], [3.0, 5.0, 7.0, 0.80000000000000004]] [[ 1. 1. 5. 0.5] [ 2. 5. 6. 5. ] [ 3. 5. 7. 0.8]] 1000x graph_array版本比您的代码快10倍。它在最大的维度上执行数组操作。我没有尝试增加altarr的大小。