how can I change the values of the diagonal of a matrix in numpy?
I checked Numpy modify ndarray diagonal, but the function there is not implemented in numpy v 1.3.0
Did you try numpy.fill_diagonal
? See the following answer and this discussion. Or the following from the documentation (although currently broken):
http://docs.scipy.org/doc/numpy/reference/generated/numpy.fill_diagonal.html
Here's another good way to do this. If you want a one-dimensional view of the array's main diagonal use:
A.ravel()[:A.shape[1]**2:A.shape[1]+1]
For the i'th superdiagonal use:
A.ravel()[i:max(0,A.shape[1]-i)*A.shape[1]:A.shape[1]+1]
For the i'th subdiagonal use:
A.ravel()[A.shape[1]*i:A.shape[1]*(i+A.shape[1]):A.shape[1]+1]
Or in general, for the i'th diagonal where the main diagonal is 0, the subdiagonals are negative and the superdiagonals are positive, use:
A.ravel()[max(i,-A.shape[1]*i):max(0,(A.shape[1]-i))*A.shape[1]:A.shape[1]+1]
These are views and not copies, so they will run faster for extracting a diagonal, but any changes made to the new array object will apply to the original array. On my machine these run faster than the fill_diagonal function when setting the main diagonal to a constant, but that may not always be the case. They can also be used to assign an array of values to a diagonal instead of just a constant.
Notes: for small arrays it may be faster to use the flat
attribute of the NumPy array.
If speed is a major issue it could be worth it to make A.shape[1]
a local variable.
Also, if the array is not contiguous, ravel()
will return a copy, so, in order to assign values to a strided slice, it will be necessary to creatively slice the original array used to generate the strided slice (if it is contiguous) or to use the flat
attribute.
Also, it was originally planned that in NumPy 1.10 and later the 'diagonal' method of arrays will return a view instead of a copy. That change hasn't yet been made though, but hopefully at some point this trick to get a view will no longer be necessary. See http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.diagonal.html
Minimal. Code.
X[np.diag_indices_from(X)] = 0.
>>> 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. ]])
If you're using a version of numpy that doesn't have fill_diagonal
(the right way to set the diagonal to a constant) or diag_indices_from
, you can do this pretty easily with array slicing:
# assuming a 2d square array
n = mat.shape[0]
mat[range(n), range(n)] = 0
This is much faster than an explicit loop in Python, because the looping happens in C and is potentially vectorized.
One nice thing about this is that you can also fill a diagonal with a list of elements, rather than a constant value (like diagflat
, but for modifying an existing matrix rather than making a new one). For example, this will set the diagonal of your matrix to 0, 1, 2, ...:
# again assuming 2d square array
n = mat.shape[0]
mat[range(n), range(n)] = range(n)
If you need to support more array shapes, this is more complicated (which is why fill_diagonal is nice...):
m[list(zip(*map(range, m.shape)))] = 0
(The list
call is only necessary in Python 3, where zip
returns an iterator.)
def replaceDiagonal(matrix, replacementList):
for i in range(len(replacementList)):
matrix[i][i] = replacementList[i]
Where size is n in an n x n matrix.