2012-03-31 2783 views
27

如何更改numpy中矩阵对角线的值?在numpy中更改矩阵对角线的值

我检查了Numpy modify ndarray diagonal,但是函数没有在numpy v 1.3.0中实现。

可以说我们有一个np.array X,我想对角线的所有值设置为0。

+1

你使用的是什么版本的numpy? 'np.diag_indices_from'在v1.4中加入了 – JoshAdel 2012-03-31 19:21:21

+0

是的,你说得对,我现在正在使用python v 1.3.0 – pacodelumberg 2012-03-31 20:57:10

+0

@LangerHansIslands希望你的意思是numpy 1.3,而不是python 1.3(它出现在90年代中期.. 。:p) – Dougal 2012-03-31 20:59:02

回答

2
def replaceDiagonal(matrix, replacementList): 
    for i in range(len(replacementList)): 
     matrix[i][i] = replacementList[i] 

如果大小是一个n×n矩阵ñ。

+3

或'n = len(replacement_list);矩阵[:n,:n] = replacement_list'。这在C中而不是在Python中循环,所以会更快。 – Dougal 2012-03-31 19:37:54

+0

@Dougal:真棒,我不知道。你能把它作为答案发布吗? – 2012-03-31 19:51:56

+0

当然,[只是](http://stackoverflow.com/a/9959707/344821)。 – Dougal 2012-03-31 21:10:09

12

如果您使用的是版本numpy的,其不具有fill_diagonal(在right way对角线设置为常数),或者diag_indices_from,你可以用数组切片做到这一点很容易地:

# assuming a 2d square array 
n = mat.shape[0] 
mat[range(n), range(n)] = 0 

这比在Python外在的循环快得多,因为循环发生在C和潜在地量化。

这样做的一个好处是,您还可以用元素列表填充对角线,而不是一个常量值(如diagflat,但用于修改现有矩阵而不是创建新矩阵)。例如,这将设置对角矩阵的对0,1,2,...:

# again assuming 2d square array 
n = mat.shape[0] 
mat[range(n), range(n)] = range(n) 

如果需要支持更多的数组的形状,这是更复杂(这就是为什么fill_diagonal是好的。 ..):

m[list(zip(*map(range, m.shape)))] = 0 

(该list通话只需要在Python 3,凡zip返回迭代器)

+0

为了让将来的读者清楚,mat [:n,:n] = 0'将整个数组/矩阵设置为0,而不仅仅是对角元素。 '拉链'版本确实做了诊断。 – gorlum0 2013-01-20 11:58:29

+0

@ gorlum0哎呀 - 谢谢你指出。我刚编辑修复它('zip'实际上并不是必需的)''。 – Dougal 2013-01-20 15:28:20

+0

酷,甚至裸'范围'。这种隐含的东西很难知道。 – gorlum0 2013-01-21 06:07:15

9

下面是做到这一点的另一个好方法。如果你想在阵列的主对角线使用的一维视图:

A.ravel()[:A.shape[1]**2:A.shape[1]+1] 

对于第i个superdiagonal使用:

A.ravel()[i:max(0,A.shape[1]-i)*A.shape[1]:A.shape[1]+1] 

对于第i次对角使用:

A.ravel()[A.shape[1]*i:A.shape[1]*(i+A.shape[1]):A.shape[1]+1] 

或者一般情况下,对于主对角线为0的第i个对角线,子对角线为负值,超对角线为正,使用:

A.ravel()[max(i,-A.shape[1]*i):max(0,(A.shape[1]-i))*A.shape[1]:A.shape[1]+1] 

这些观点,而不是拷贝,那么他们将运行用于提取对角线快,但新的数组对象所做的任何更改将应用​​到原始数组。 在我的机器上,当将主对角线设置为常量时,它们的运行速度比fill_diagonal函数快,但情况并非总是如此。它们也可以用来为一个对角线而不是一个常量赋值一个数组。

注意:对于小阵列,使用NumPy数组的flat属性可能会更快。 如果速度是一个主要问题,它可能是值得的A.shape[1]本地变量。 此外,如果数组不连续,ravel()将返回一个副本,因此,为了将值分配给跨步切片,需要创建切片用于生成跨步切片的原始数组(如果它是连续的)或使用flat属性。

此外,最初计划在NumPy 1.10及更高版本中,数组的“对角线”方法将返回视图而不是副本。 虽然这个改变还没有做出,但希望在某个时候这个伎俩来获得一个观点将不再是必要的。 见http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.diagonal.html

+0

尼斯和哈克,我喜欢它!唯一需要注意的是我认为你会得到['np.fill_diagonal'文档]中描述的'wrap = True'行为(http://docs.scipy.org/doc/numpy/reference/generated/numpy.fill_diagonal.html )。你也许可以解决,为你的切片添加足够的停止值。 – Jaime 2013-07-23 04:41:21

+0

谢谢,很好。我只是编辑它来解决这个问题和其他一些事情。 – IanH 2013-07-23 05:28:56

1
>>> a = numpy.random.rand(2,2) 
>>> a 
array([[ 0.41668355, 0.07982691], 
     [ 0.60790982, 0.0314224 ]]) 
>>> a - numpy.diag(numpy.diag(a)) 
array([[ 0.  , 0.07982691], 
     [ 0.60790982, 0.  ]]) 
4

最小。码。

X[np.diag_indices_from(X)] = 0. 

screenshot

1

你可以做到以下几点。

假设您的矩阵是4 * 4矩阵。

indices_diagonal = np.diag_indices(4) 

yourarray[indices_diagonal] = Val