假设我们有一个矩阵和一个索引列表:
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或不使用numpy对其进行谷歌搜索,但找不到正确的语法。
是否有我在此描述的解决方案,但是我使用的语法错误?或其他任何改进建议?
答案 0 :(得分: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
答案 1 :(得分:1)
因此,假设您犯了一个错误并且您的意思是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]
答案 2 :(得分:1)
由于在问题中提到了效率问题,所以应该做一些进一步的分析。
首先,代码看起来像是使用伴随矩阵来找到矩阵逆的代码。除非该特定方法对项目很重要,否则标准np.linalg.inv()
几乎肯定会比我们在这里编写的任何东西都要快。而且,在许多应用中,您可以摆脱线性方程组的求解,而不必寻找逆并乘以它,从而将运行时间减少一半或更多。
第二,关于有效的numpy代码的任何讨论都需要解决视图而不是副本。与标准浮点算法相比,内存分配,写入内存和内存释放都是非常昂贵的操作。这并不是说它们很慢,但是您可以注意到代码存储有效代码与几乎其他所有代码的速度之间存在一个或两个数量级的差异。这就是我所知道的最快执行持久同源性计算的全部前提。
所有其他答案(在撰写本文时)会为其使用的数据创建副本,并将该信息显式存储在新变量sub_matrix
中。不可能用副本创建每个花式索引的矩阵,但是通常可以执行等效的操作。
例如,如果这确实是一组关于伴随矩阵的计算,以便您的indexes
变量由除一个索引外的所有索引组成(在您的示例中,除中间索引),那么我们可以对所有指标求和,然后减去不需要的指标,而不是对所有预期指标进行显式求和。结果是所有中间矩阵都是视图,而不是副本,从而避免了昂贵的内存分配。在我的机器上,对于给定的3x3微型示例,此速度快一倍,对于500x500矩阵,该速度快十倍。
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]
当然,如果您可以使用切片来表示您正在做的事情,并且您不必像我一样通过额外的操作来解决该问题,它甚至会更快,但是您给出的示例并不容易允许切片