【问题标题】:Python - sum the intersection of rows and columns in a matrixPython - 对矩阵中的行和列的交集求和
【发布时间】:2018-08-21 09:02:43
【问题描述】:

假设我们有一个矩阵和一个索引列表:

adj_mat = np.array([[1,2,3],
                     [4,5,6],
                     [7,8,9]])
indexes = [0,2]

我想要的是对我们通过索引列表的行和列的交集得到的子矩阵对应的行和列求和。在这种情况下,它将是:

 sub_matrix =  ([[1,3]
                 [7,9]])
 result_rows = [4,16]
 result_columns = [8,12]

但是,我多次使用相同的原始矩阵和不同的索引列表进行此计算,因此我正在寻找一种有效的解决方案,而无需每次迭代都创建子矩阵。到目前为止,我的解决方案是(以及分别用于列):

def sum_rows(matrix, indexes):
    sum_r = [0]*len(indexes)
    for i in range(len(indexes)):
        for j in indexes:
            sum_r[i] += matrix.item(indexes[i], j)
    return sum_r

我正在寻找一种更有效的算法,因为我记得有一种方法看起来像这样,可以对索引中的所有行(或列?)求和:

matrix.sum(:, indexes)
matrix.sum(indexes, indexes)

我假设我需要的是第二行,如果它存在的话。我尝试用谷歌搜索它,无论有没有 numpy,但找不到正确的语法。

是否有我在此处描述的解决方案,但我只是使用了错误的语法?或者有什么其他的改进建议?

【问题讨论】:

  • 我不明白函数f 采用adj_matindexes 产生sub_matrix。你如何从[[1,2,3],[4,5,6],[7,8,9]] 得到[[1, 6], [7, 9]][1, 3] 也不是 3 x 3 矩阵的索引。你的意思是[0, 2]
  • 是的,我只是做了一个类似人类的例子,而不是来自编码。谢谢

标签: python matrix sum


【解决方案1】:

IIUC:

import numpy as np

adj_mat = np.array([[1,2,3],
                    [4,5,6],
                    [7,8,9]])

indexes = np.array([1, 3]) - 1
sub_matrix = adj_mat[np.ix_(indexes, indexes)]
result_rows, result_columns = sub_matrix.sum(axis=1), sub_matrix.sum(axis=0)

结果:

array([ 4, 16]) # result_rows
array([ 8, 12]) # result_columns

【讨论】:

    【解决方案2】:

    所以假设你犯了一个错误,你的意思是 indexes = [0,2]sub_matrix = [[1,3], [7,9]],那么这应该做你想做的事

    def sum_sub(matrix, indices):
        """
        Returns the sum of each row and column (as a tuple)
        for each index in indices (as an array)
        """
        # note that this sub matrix does not copy any data from matrix,
        # it is a "view" which simply holds a reference to matrix
        sub_mat = matrix[np.ix_(indices, indices)]
        return sub_mat.sum(axis=1), sub_mat.sum(axis=0)
    
    sum_row, sum_col = sum_sub(np.arange(1,10).reshape((3,3)), [0,2])
    

    这个结果是

    sum_col  # --> [ 8 12]
    sum_row  # --> [ 4 16]
    

    【讨论】:

      【解决方案3】:

      由于问题中提到了效率点,因此可能应该做一些进一步的分析。

      首先,代码看起来像使用伴随矩阵找到矩阵逆的代码。除非该特定方法对项目很重要,否则标准 np.linalg.inv() 几乎肯定会比我们在这里编写的任何方法都要快。此外,在许多应用程序中,您可以解决线性方程组,而不是找到一个逆并乘以它,从而将运行时间再次缩短一半或更多。

      其次,任何关于高效 numpy 代码的讨论都需要解决 views 而不是 copies。与标准浮点运算相比,内存分配、写入内存和内存释放都是极其昂贵的操作。这并不是说它们很慢,但是您可以注意到代码内存高效代码的速度与几乎任何其他代码的速度相差一个或两个数量级。这就是我所知道的最快实现持久同调计算背后的全部前提。

      所有其他答案(在撰写本文时)都会创建他们正在使用的数据的副本,并将该信息明确存储在新变量 sub_matrix 中。不可能使用副本创建每个花式索引矩阵,但通常可以执行等效操作。

      例如,如果这确实是对伴随矩阵的一组计算,那么您的 indexes 变量包含 除一个 的可用索引(在您的示例中,除中间索引之外的所有),那么我们可以对所有索引求和,然后减去我们不关心的那个,而不是显式地对所有预期的索引求和。效果是所有中间矩阵都是视图而不是副本,从而避免了昂贵的内存分配。在我的机器上,对于给定的微小 3x3 示例,速度是其两倍,对于 500x500 矩阵,速度是 10 倍。

      bad_row = 1
      bad_col = 1
      
      result_rows = (np.sum(adj_mat, axis=1)-adj_mat[:,bad_col])[np.arange(adj_mat.shape[0])!=bad_row]
      result_cols = (np.sum(adj_mat, axis=0)-adj_mat[bad_row,:])[np.arange(adj_mat.shape[1])!=bad_col]
      

      当然,如果您可以使用切片来表示您正在做的任何事情,并且您不必像我那样通过额外的操作来解决问题,那么它会更快,但是您给出的示例并不容易允许切片.

      【讨论】:

      • 感谢您的详细回答!我的计算与矩阵求逆无关,而是与动态子图的计算以及每个子图的度数有关。为此,为了找到子图的度数,我选取其中的节点(行)并仅在子图(列)内检查它们的邻居。我看到您使用了“adj_mat [:,bad_row]”。我不能把它用作 'adj_mat[good_columns,good_rows]' 吗?
      • 实际上在程序中很多次我只是将一个节点从一个子图移动到另一个。在这种情况下,我需要特定行与索引中的列的总和,反之亦然。你会怎么做?我想一个简单的 for 循环就足以完成该任务
      • @NaftaliWaxman 首先,没有adj_mat[good_columns,good_rows] 通常不会返回视图,因为通常不能变成切片。它在语法上有效(我认为),但它不能从避免内存分配的效率收益中受益。至于第二点,我认为我缺乏细节。作为另一个问题处理可能会更好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-28
      相关资源
      最近更新 更多