为什么访问稀疏矩阵代价高昂?

时间:2014-03-20 17:11:10

标签: python numpy scipy

我有一个1034_by_1034稀疏矩阵(scipy.sparse.csr.csr_matrix),它基本上代表图的邻接矩阵。我想检查一些元素是否为1。但我发现这是一个非常缓慢的操作。在if statement代码以 11 秒运行之前,但是当我启用if检查时,它需要 40 秒!

这是我的代码段:

target = list()
for edge_id in edges_ids:
    v1_label, v2_label = from_edgeID_to_vertix_labels(edge_id) #fast
    v1_index = g.get_v_index(v1_label) #fast
    v2_index = g.get_v_index(v2_label) #fast

    #if the following chunk is enabled, it becomes slow!     
    if A[v1_index, v2_index] == 1:
        target.append(1)
    else:
        target.append(0)
g.target = target

2 个答案:

答案 0 :(得分:1)

原因很可能是在CSR(或CSC格式)中从稀疏矩阵中获取单个值,给定索引( i j ) , 是非常昂贵的。这些稀疏矩阵表示的算法通常不是为了这样做而设计的:它们被设计成使用它们在顺序通过数组时找到的索引。

在CSR中,当您查找一行时,您可以有效地获得列索引数组和相应的值。如果您正在获取单个值,则必须通过一小部分列索引(一般未排序)进行线性搜索,以查看它是否存在(否则值为零);如果找到,则从值数组中选择值并返回它。它可能看起来有点像ad-hoc C (这是说明):

/* Obviously silly CSR matrix typedef */
typedef struct sparse_s {
    int    row[nnz+1];
    int    col[nnz];
    double value[nnz];
} sparse_s;


double spGetValue(sparse_s const* s, int i, int j)
{
    int k;

    for(k=s->row[i]; k<s->row[i+1]; k++) {
        if( j == s->col[k] ) {
            return s->value[k];
        }
    }
    return 0.0;
}

所以,如果你要在每一行上平均10个元素,你必须为每个访问搜索一个十元素数组。对于像SpMV这样的算法来说,这不是一个问题,它们在找到它们时使用列索引。如果你像密集的MM一样实现SpMV,获取每个值,即使你有一些跳过零的神秘方式,它也会非常缓慢。如果您觉得不好,元素插入到CSR / CSC矩阵中是非常昂贵的,而且(几乎)从未完成。

简而言之,您可以通过重新组织代码来获得更好的结果,以便您直接迭代CSR矩阵的三个向量,或者针对此特定问题使用不同的稀疏矩阵表示。

它可能更像是“Pythoney”,但是如果矩阵表示和访问方法是,那么即使在 C 的最佳情况下,我也不希望你的代码表现良好。保留

答案 1 :(得分:-1)

在这种情况下,最好使用嵌套的defaultdict:

from collections import defaultdict
A = defaultdict(lambda : defaultdict(int))
# Example of how to set an element in the adjacency matrix:
A[1][2] = 1

但是,这不支持numpy或scipy提供的任何矩阵操作,但对于特定用例应该很快。