我正在尝试编写一个带有函数的解决方案,并设置中心对角线值(即沿A [0,0],A [1,1],....,A [N,N] )基于对角单元下方列中的值求和。
一个例子:
A = np.array([[0, 0, 0],
[3, 0, 0],
[4, 2, 0]])
B = function_to_be_built(A)
B = np.array([[7, 0, 0],
[3, 2, 0],
[4, 2, 0]])
您可以看到单元格[0,0] = 3 + 4 = 7和单元格[1,1]的加法运算符,2 = 2。
当然,使用for
循环可以相对容易地实现这一点,但代码设计在中央内核中,因此效率至关重要。我觉得应该有一种方法可以使用numpy来有效地实现这一点....比如使用np.tril
,所以只选择对角线以下的值?
有人可以帮助我找到解决方案吗?
感谢。
答案 0 :(得分:2)
你可以取A
的下三角部分,按列加总,转换为对角矩阵,然后加回A
:
A + np.eye(A.shape[0]) * np.tril(A).sum(axis=0)
答案 1 :(得分:2)
以下是使用np.add.at
y, x = np.tril_indices(len(A), -1)
np.add.at(A, [x,x], A[y,x])
这会将低于对角线的列原点添加到相应的对角线元素中。如果不保证这些为零,请执行
A[np.arange(len(A)), np.arange(len(A))] = 0
之前。
请注意,在任何一种情况下,此方法都不要求上三角形为零。
如果在相同大小的矩阵上重复此操作,则可以预先计算索引并将其展平以提高性能。
# compute once
flatinds = np.ravel_multi_index((y, x), A.shape)
flatdiag = np.ravel_multi_index((x, x), A.shape)
flshdiag = (len(A)+1) * np.arange(len(A))
# use every iteration
Afl = A.ravel()
Afl[flshdiag] = 0 # only if necessary
np.add.at(Afl, flatdiag, Afl[flatinds])
无法抗拒一个非常快的人。它利用线性索引和np.add.reduceat
。由于大多数总和沿着较长的列延伸,因此在计算的开始和结束时进行完整(非延迟)转置是值得的。对于N> = 5,它始终胜过所有其他竞争者。如果你可以保持矩阵(Fortran)顺序中涉及的矩阵,那么甚至可以保存两个转置,在这种情况下,它比从N == 3开始的所有其他转置要快。
# precompute this (A.shape == (N, N))
finds = np.c_[N * np.arange(N), 1 + (N+1) * np.arange(N)].ravel()[1:-2].copy()
def PPt(A):
A = A.T.copy()
Af = A.ravel()
Af[:-1:N+1] = np.add.reduceat(Af[:-N], finds)[::2]
Af[-1] = 0
return A.T.copy()
答案 2 :(得分:1)
如果你确定对角线和上对角线都用零填充,你可以这样做:
In [43]: B = A + np.diag(A.sum(axis=0))
In [44]: B
Out[44]:
array([[7, 0, 0],
[3, 2, 0],
[4, 2, 0]])
如果您不能保证这些区域为零,您可以这样做:
In [62]: B = A + np.diag(np.tril(A, -1).sum(axis=0))
In [63]: B
Out[63]:
array([[7, 0, 0],
[3, 2, 0],
[4, 2, 0]])