如何在numpy数组中就地填充上三角形为零?
有什么好的方法可以直接在一个numpy数组的下三角部分填充零,而不需要像下面这样做:
a=np.random.random((5,5))
a = np.triu(a)
因为np.triu返回的是一个副本,而不是视图。最好是这个方法不需要使用列表索引,因为我在处理很大的数组。
3 个回答
0
import numpy as np n=3 A=np.zeros((n,n)) for p in range(n): A[0,p] = p+1 if p >0 : A[1,p]=p+3 if p >1 : A[2,p]=p+4
创建一个从1开始的上三角矩阵
2
如果你的速度和内存使用还有限制,并且可以使用Cython,那么写一个简单的Cython函数就能满足你的需求。这里有一个专门为C语言连续数组设计的工作版本,支持双精度值。
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef make_lower_triangular(double[:,:] A, int k):
""" Set all the entries of array A that lie above
diagonal k to 0. """
cdef int i, j
for i in range(min(A.shape[0], A.shape[0] - k)):
for j in range(max(0, i+k+1), A.shape[1]):
A[i,j] = 0.
这个方法的速度应该比任何涉及到乘以一个大临时数组的版本快很多。
23
深入了解triu
的内部工作原理,你会发现它其实就是把输入的数组和tri
的输出结果相乘。
所以你可以直接把数组和tri
的输出结果相乘:
>>> a = np.random.random((5, 5))
>>> a *= np.tri(*a.shape)
>>> a
array([[ 0.46026582, 0. , 0. , 0. , 0. ],
[ 0.76234296, 0.5298908 , 0. , 0. , 0. ],
[ 0.08797149, 0.14881991, 0.9302515 , 0. , 0. ],
[ 0.54794779, 0.36896506, 0.92901552, 0.73747726, 0. ],
[ 0.62917827, 0.61674542, 0.44999905, 0.80970863, 0.41860336]])
和triu
一样,这样做还是会创建一个新的数组(就是tri
的输出),但至少这个操作是在原数组上进行的。这里的“splat”是个小技巧;如果你想做得更稳妥,可以考虑基于triu
的完整版本来写你的函数。不过要注意,你仍然可以指定对角线:
>>> a = np.random.random((5, 5))
>>> a *= np.tri(*a.shape, k=2)
>>> a
array([[ 0.25473126, 0.70156073, 0.0973933 , 0. , 0. ],
[ 0.32859487, 0.58188318, 0.95288351, 0.85735005, 0. ],
[ 0.52591784, 0.75030515, 0.82458369, 0.55184033, 0.01341398],
[ 0.90862183, 0.33983192, 0.46321589, 0.21080121, 0.31641934],
[ 0.32322392, 0.25091433, 0.03980317, 0.29448128, 0.92288577]])
我现在看到问题的标题和内容描述的是相反的行为。为了以防万一,这里是如何用零填充下三角形的方法。这需要你指定-1
的对角线:
>>> a = np.random.random((5, 5))
>>> a *= 1 - np.tri(*a.shape, k=-1)
>>> a
array([[0.6357091 , 0.33589809, 0.744803 , 0.55254798, 0.38021111],
[0. , 0.87316263, 0.98047459, 0.00881754, 0.44115527],
[0. , 0. , 0.51317289, 0.16630385, 0.1470729 ],
[0. , 0. , 0. , 0.9239731 , 0.11928557],
[0. , 0. , 0. , 0. , 0.1840326 ]])