Python:由于重复索引

时间:2015-09-16 20:35:12

标签: python arrays numpy scipy

我的情况如下:

我有一系列的结果,比方说 S = np.array([2,3,10,-1,12,1,2,4,4]),我想根据可能重复元素(没有特定模式)的列索引数组插入scipy.sparse.lil _ matrix M的最后一行,例如: j = np.array([3,4,5,14,15,16,3,4,5])

当重复列索引时,S中相应值的总和应插入矩阵M中。因此,在上面的示例中,结果[4,7,14]应放在[3,4,5]的最后一行的M列中。换句话说,我想实现类似的东西:

M[-1,j] = np.array([2+2,3+4,10+4,-1,12,1])

计算速度对我的程序非常重要,因此我应该避免使用循环。期待您的聪明解决方案!谢谢!

2 个答案:

答案 0 :(得分:0)

您可以使用defaultdict将M列索引映射到它们的值,并使用map函数更新此defaultdict,如下所示:

from collections import defaultdict

d = defaultdict(int) #Use your array type here
def f(j, s):
    d[j] += s
map(f, j, S)
M[-1, d.keys()] = d.values() #keys and values are always in the same order

如果您不想无用地创建map列表,则可以使用filter而不是None

d = defaultdict(int) #Use your array type here
def g(e):
    d[e[1]] += S[e[0]]
filter(g, enumerate(j))
M[-1, d.keys()] = d.values() #keys and values are always in the same 

答案 1 :(得分:0)

这种求和是sparse矩阵的正常行为,尤其是csr格式。

定义3个输入数组:

In [408]: S = np.array([2,3,10,-1,12,1,2,4,4])
In [409]: j=np.array([3,4,5,14,15,16,3,4,5])
In [410]: i=np.ones(S.shape,int)

coo格式按原样使用这3个数组,无需更改

In [411]: c0=sparse.coo_matrix((S,(i,j)))
In [412]: c0.data
Out[412]: array([ 2,  3, 10, -1, 12,  1,  2,  4,  4])

但是当转换为csr格式时,它会对重复的索引求和:

In [413]: c1=c0.tocsr()
In [414]: c1.data
Out[414]: array([ 4,  7, 14, -1, 12,  1], dtype=int32)
In [415]: c1.A
Out[415]: 
array([[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  4,  7, 14,  0,  0,  0,  0,  0,  0,  0,  0, -1, 12,  1]], dtype=int32)

coo转换为密集或数组c0.A时也会进行求和。

以及转换为lil时:

In [419]: cl=c0.tolil()
In [420]: cl.data
Out[420]: array([[], [4, 7, 14, -1, 12, 1]], dtype=object)
In [421]: cl.rows
Out[421]: array([[], [3, 4, 5, 14, 15, 16]], dtype=object)

lil_matrix不会直接接受(data,(i,j))输入,因此如果您是目标,则必须通过coo

http://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.sparse.coo_matrix.html

  

默认情况下,转换为CSR或CSC格式时,重复(i,j)条目将汇总在一起。这有利于有限元矩阵等的有效构造。 (见例)

要在现有lil中插入,请使用中间csr

In [443]: L=sparse.lil_matrix((3,17),dtype=S.dtype)
In [444]: L[-1,:]=sparse.csr_matrix((S,(np.zeros(S.shape),j)))
In [445]: L.A
Out[445]: 
array([[ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  4,  7, 14,  0,  0,  0,  0,  0,  0,  0,  0, -1, 12,  1]])

此声明比使用csr_matrix的声明更快;

L[-1,:]=sparse.coo_matrix((S,(np.zeros(S.shape),j)))

如果您真的担心速度,请检查L.__setitem__。在手边看起来它通常会将稀疏矩阵转换为数组

L[-1,:]=sparse.coo_matrix((S,(np.zeros(S.shape),j))).A

需要同样的时间。对于像这样的小测试用例,创建中间矩阵的开销可能会花费任何时间来添加这些重复索引。

通常,无论是否进行此求和,向现有稀疏矩阵插入或附加值都很慢。在可能的情况下,最好先为整个矩阵创建dataij数组,然后再制作稀疏矩阵。