【问题标题】:Summing selected elements of a matrix in Python在Python中对矩阵的选定元素求和
【发布时间】:2019-08-24 02:35:57
【问题描述】:

我有一个 [n x n] 矩阵,其中包含属于不同组的值,以及一个 [1 x n] 向量定义每个元素所属的组。 (n 通常 ~1E4,在本例中 n=4)

我想计算一个将属于同一组的所有元素相加得到的矩阵。

我使用 np.where() 来计算每个组的元素所在的索引。 当我使用计算的索引时,我没有获得预期的元素,因为我选择了位置对而不是范围(我习惯于 Matlab,在这里我可以简单地选择 M(idx1,idx2) )。

import numpy as np

n=4
M = np.random.rand(n,n)
print(M)

# This vector defines to which group each element belong
belongToGroup = np.array([0, 1, 0, 2])

nGroups=np.max(belongToGroup);

# Calculate a matrix obtained by summing elements belonging to the same group
M_sum = np.zeros((nGroups+1,nGroups+1))
for g1 in range(nGroups+1):
    idxG1 = np.where(belongToGroup==g1)
    for g2 in range(nGroups+1):
        idxG2 = np.where(belongToGroup==g2)
        print('g1 = ' + str(g1))
        print('g2 = ' + str(g2))
        print(idxG1[0])
        print(idxG2[0])
        print(M[idxG1[0],idxG2[0]])
        print(np.sum(M[idxG1[0],idxG2[0]]))
        M_sum[g1,g2]=np.sum(M[idxG1[0],idxG2[0]])

print('')
print('Example of the problem:')
print('Elements I would like to sum to obtain M_sum[0,0]')
print(M[0:2,0:2])
print('Elements that are summed instead')
print(M[[0,1],[0,1]])

问题示例: 在上面的示例中,元素 M_sum[0,0] 应该是 M[0,0]、M[0,1]、M[1,0] 和 M[1,1] 的总和 相反,它被计算为 M[0,0] 和 M[1,1] 的总和

【问题讨论】:

    标签: python arrays numpy matrix indices


    【解决方案1】:

    在 MATLAB 中,使用 2 个列表(实际上是矩阵)进行索引会选择一个块。另一方面,numpy 尝试相互广播索引数组,并返回选定的点。它的行为与 sub2ind 在 MATLAB 中的行为接近。

    In [971]: arr = np.arange(16).reshape(4,4)                                      
    In [972]: arr                                                                   
    Out[972]: 
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15]])
    In [973]: i1, i2 = np.array([0,2,3]), np.array([1,2,0])                         
    

    使用 2 个相同大小的一维数组进行索引:

    In [974]: arr[i1,i2]
    Out[974]: array([ 1, 10, 12])
    

    这实际上返回[arr[0,1], arr[2,2], arr[3,0]],每个匹配索引点一个元素。

    但如果我将一个索引变成“列向量”,它会从行中选择,而i2 从列中选择。

    In [975]: arr[i1[:,None], i2]                                                   
    Out[975]: 
    array([[ 1,  2,  0],
           [ 9, 10,  8],
           [13, 14, 12]])
    

    MATLAB 使块索引变得容易,而单独访问则更加困难。在numpy 中,块访问有点困难,尽管底层机制是相同的。

    在您的示例中,i1[0]i2[0] 可以是如下数组:

    array([0, 2]), array([3])
    (2,) (1,)
    

    形状 (1,) 数组可以与 (2,) 或 (2,1) 数组一起广播。如果 is[0]np.array([0,1,2])(一个不能与 (2,) 数组配对的 (3,) 数组),您的代码将会失败。但是使用 (2,1) 会产生 (2,3) 块。

    【讨论】:

    • 感谢您的回复。我尝试更改以下行: M_sum[g1,g2]=np.sum(M[idxG1[0],idxG2[0]]) 如下: M_sum[g1,g2]=np.sum(M[idxG1[ :,None],idxG2[0]]) 也许我理解错了。我收到一个错误“元组索引必须是整数,而不是元组”
    • 您仍然需要使用[0]。由where 生成的idxG1tuple,源的每个维度一个元素。 idxG1[0] 为您提供第一维的索引数组。 idxG1[0][:,None] 为其添加了一个维度。那个“:,None”表达式实际上是一个tuple。在 Python 中,几乎每个包含逗号的表达式都是一个元组 :)
    【解决方案2】:

    您可以使用np.ix_ 来获得matlab-ish 行为:

    A = np.arange(9).reshape(3, 3)
    A[[1,2],[0,2]]
    # array([3, 8])
    A[np.ix_([1,2],[0,2])]
    # array([[3, 5],
    #        [6, 8]])
    

    在幕后,np.ix_ 做了@hpaulj 详细描述的事情:

    np.ix_([1,2],[0,2])
    # (array([[1],
    #        [2]]), array([[0, 2]]))
    

    您可以将其应用于您的具体问题,如下所示:

    M = np.random.randint(0, 10, (n, n))
    M
    # array([[6, 2, 7, 1],
    #        [6, 7, 9, 5],
    #        [9, 4, 3, 2],
    #        [3, 1, 7, 9]])
    idx = np.array([0, 1, 0, 2])
    
    ng = idx.max() + 1
    out = np.zeros((ng, ng), M.dtype)
    np.add.at(out, np.ix_(idx, idx), M)
    out
    # array([[25,  6,  3],
    #        [15,  7,  5],
    #        [10,  1,  9]])
    

    顺便说一句:有一个更快但不太明显的解决方案,它依赖于平面索引:

    np.bincount(np.ravel_multi_index(np.ix_(idx, idx), (ng, ng)).ravel(), M.ravel(), ng*ng).reshape(ng, ng)
    # array([[25.,  6.,  3.],
    #        [15.,  7.,  5.],
    #        [10.,  1.,  9.]])
    

    【讨论】:

    • 谢谢,这也有效。总结一下:错误:M_sum[g1,g2]=np.sum(M[idxG1[0],idxG2[0]]) 正确 1(谢谢@hpaulj) M_sum[g1,g2]=np.sum(M[ idxG1[0][:,None],idxG2[0]]) 正确 2(谢谢 Paul Panzer) M_sum[g1,g2]=np.sum(M[np.ix_(idxG1[0],idxG2[0] )])
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-28
    • 2023-03-03
    • 2017-03-05
    • 2021-12-18
    • 2021-09-20
    • 1970-01-01
    • 2017-09-30
    相关资源
    最近更新 更多