我需要将矩阵的对角线元素设置为Inf。
一个简单的方法是使用np.fill_diagonal
。
np.fill_diagonal(my_matrix, float('inf')
但是,fill_diagonal
修改输入矩阵,而不是返回对角填充的新矩阵。这对我不管用。我需要填充对角线而不修改原始矩阵。
当然,我可以克隆原始矩阵,所以我总是保留原始矩阵的副本。然而,我并不真的喜欢这个解决方案,因为我将经常更新我的原始矩阵,因此,我将不得不复制它,每次我需要对角是inf。
是否有一个函数可以执行与fill_diagonal
相同的操作,但不修改输入矩阵?类似于:
new_matrix = np.fill_diagonal(original_matrix, float('inf')
为什么我需要这个:
我的矩阵是点之间的距离矩阵,我想在每一步计算两个最近的点。当然,这个矩阵的对角线是0(因为从一个点到它本身的距离是0)。因此,我的解决方案,以确保我不采取相同的一点,是设置对角为Inf。
然而,一旦找到这两个点,我需要计算这两个点与其余点之间距离的平均值,所以我实际上需要对角值为0而不是Inf。
目前我所做的是:
但是,我不喜欢将对角线设置为Inf,然后返回到0,我更喜欢将一个函数传递给argmax
,该函数返回带有Inf填充的对角线的数据,而不实际修改矩阵数据。
类似于:
idx = np.argmin(return_filled_diagonals(data, float('Inf'))
# here I can operate with data as usual since it has not been modified.
发布于 2017-05-03 13:32:40
orig_mat = np.array([[1.2,2,3],[4,5,6],[7,8,9]])
#set diagonal to inf without making a copy of the array.
orig_mat + np.where(np.eye(orig_mat.shape[0])>0,np.inf,0)
array([[ inf, 2., 3.],
[ 4., inf, 6.],
[ 7., 8., inf]])
#the original array remains untorched.
print(orig_mat)
[[ 1.2 2. 3. ]
[ 4. 5. 6. ]
[ 7. 8. 9. ]]
发布于 2017-05-03 13:47:19
方法#1
您正在寻找的魔术是在NumPy strides
中,它可以让我们看到没有对角线元素的数组,因此不再占用内存空间。下面是实现这样一个视图的方法-
def nodiag_view(a):
m = a.shape[0]
p,q = a.strides
return np.lib.stride_tricks.as_strided(a[:,1:], (m-1,m), (p+q,q))
让我们来看看一个样本运行来验证它是一个视图-
In [124]: a # Input array
Out[124]:
array([[ 0, 61, 43, 26, 21],
[20, 0, 78, 29, 64],
[34, 49, 0, 64, 60],
[36, 96, 67, 0, 75],
[36, 85, 40, 74, 0]])
# Get the no-diag view
In [125]: a_nodiag = nodiag_view(a)
# Lets's verify by changing elements in the view and that should change
# elements in the original array too
In [126]: a_nodiag[:] = 999
In [127]: a
Out[127]:
array([[ 0, 999, 999, 999, 999],
[999, 0, 999, 999, 999],
[999, 999, 0, 999, 999],
[999, 999, 999, 0, 999],
[999, 999, 999, 999, 0]])
最后,让我们看看如何设置它来解决你的整个问题-
def argmin_without_diag(a):
a_nodiag = nodiag_view(a)
idx_nodiag = np.argmin(a_nodiag)
m = a.shape[0]
idx = idx_nodiag + np.unravel_index(idx_nodiag, (m-1,m))[0]+1
return np.unravel_index(idx, a.shape)
样本运行-
In [142]: a
Out[142]:
array([[ 0, 60, 79, 55, 77],
[62, 0, 86, 84, 25],
[32, 96, 0, 74, 89],
[24, 33, 64, 0, 93],
[14, 74, 30, 44, 0]])
In [143]: argmin_without_diag(a)
Out[143]: (4, 0)
方法#2
如果您同时考虑内存和性能,可以暂时将对角线设置为infnite
,然后获取argmin
索引,然后返回原始的对角线值。因此,输入数组实际上是不变的。执行过程会是这样的-
def argmin_without_diag_replacement(a):
# Store diagonal values
vals = a.ravel()[::a.shape[1]+1].copy()
# Set diag ones as infinites
a.ravel()[::a.shape[1]+1] = np.inf
# Get argmin index
idx = np.argmin(a)
# Put back the original diag values
a.ravel()[::a.shape[1]+1] = vals
return np.unravel_index(idx, a.shape)
因此,对于(n x n)
形状的数组,临时数组将只有n
元素。
样本运行-
In [237]: a
Out[237]:
array([[ 0., 95., 57., 75., 92.],
[ 37., 0., 69., 71., 62.],
[ 42., 72., 0., 30., 57.],
[ 41., 80., 94., 0., 26.],
[ 36., 45., 71., 76., 0.]])
In [238]: argmin_without_diag_replacement(a)
Out[238]: (3, 4)
运行时测试
In [271]: a = np.random.randint(11,99,(1000,1000)).astype(float)
In [272]: np.fill_diagonal(a,0)
In [273]: %timeit argmin_without_diag(a)
1000 loops, best of 3: 1.76 ms per loop
In [274]: %timeit argmin_without_diag_replacement(a)
1000 loops, best of 3: 688 µs per loop
发布于 2017-05-03 11:54:53
据我所知,您希望找到矩阵最小值的索引,但不包括对角线元素:
orig_mat = np.array([[1.2,2,3],[4,5,6],[7,8,9]])
min_idx = np.argmin(orig_mat+np.multiply(np.eye(orig_mat.shape[0]),1e9))
https://stackoverflow.com/questions/43758949
复制相似问题