How to access the diagonals of a matrix and change the value?

隐身守侯 提交于 2019-12-02 18:07:39

问题


I have 8x8 matrix where I have 15 diagonals. upper left corner “diagonal 1” and the lower right corner “diagonal 15”. I want to zero out the specific sets of diagonals like {9, 10, 11, 12, 13, 14, 15} or {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}. Anyone please give me solution?


回答1:


I believe you can use:

M = M - diag(diag(M,k),k);

where k is 0 for the main diagonal, negative for the lower diagonals (up to -7), positive for the upper diagonals (up to 7).

EDIT: My bad, this only zero out one of the diagonal of your choice. You can repeat the process for all the diagonals you want to zero out but that might not be optimal:

for k=[9 10 11 12 13 14 15]
    M = M - diag(diag(M,k-length(M)),k-length(M));
end



回答2:


I'm not sure if I understand your question correctly. Are you trying to zero out some subset of elements on the main diagonal, or are you trying to zero out an entire diagonal? Either way, you can look into using Matlab's "diag" function.

If you want to just zero out some elements on the main diagonal, you could use something like:

% A is a 15 x 15 matrix, want to zero out {1,2,3,8}th elements on the diagonal
d = diag(A); % diagonal elements of A
d([4:7 9:15]) = 0; % zero out the elements you want to KEEP
A = A - diag(d); % diag d is a diagonal matrix with d on the main diagonal

But it would be easier with a for loop:

for i=[1,2,3,8]
A(i,i) = 0;
end

Zeroing out the nth diagonal of A is actually easier:

Say you want to zero the 3rd diagonal, you would do: A = A - diag(diag(A,3),3);




回答3:


I think my diagonal run the other way but you should get the idea.

Python code:

import numpy as np

matrix = np.ones((8,8))

print "matrix = \n", matrix

# Need to map "diagnals" to starting row & offset, this is for 8x8

start_map = {}

start_map[ 0] = (0, 7)
start_map[ 1] = (0, 6)
start_map[ 2] = (0, 5)
start_map[ 3] = (0, 4)
start_map[ 4] = (0, 3)
start_map[ 5] = (0, 2)
start_map[ 6] = (0, 1)
start_map[ 7] = (0, 0)
start_map[ 8] = (1, 0)
start_map[ 9] = (2, 0)
start_map[10] = (3, 0)
start_map[11] = (4, 0)
start_map[12] = (5, 0)
start_map[13] = (6, 0)
start_map[14] = (7, 0)

# Zero out selected "diagnal"

M, N = matrix.shape

for i in xrange(15):

    new_matrix = np.array(matrix)

    m, n = start_map[i]

    while m < M and n < N:

        new_matrix[m, n] = 0.0

        m += 1
        n += 1

    print "'diag' = %d\n" % i, new_matrix

Here's the truncated output:

matrix = 
[[ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]]
'diag' = 0
[[ 1.  1.  1.  1.  1.  1.  1.  0.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]]
'diag' = 3
[[ 1.  1.  1.  1.  0.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  0.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  0.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  0.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]]
'diag' = 7
[[ 0.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  0.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  0.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  0.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  0.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  0.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  0.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  0.]]
'diag' = 8
[[ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 0.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  0.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  0.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  0.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  0.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  0.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  0.  1.]]
'diag' = 9
[[ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.]
 [ 0.  1.  1.  1.  1.  1.  1.  1.]
 [ 1.  0.  1.  1.  1.  1.  1.  1.]
 [ 1.  1.  0.  1.  1.  1.  1.  1.]
 [ 1.  1.  1.  0.  1.  1.  1.  1.]
 [ 1.  1.  1.  1.  0.  1.  1.  1.]
 [ 1.  1.  1.  1.  1.  0.  1.  1.]]



回答4:


If i follow you, here's a simple method:

a       = rand(8,8);
indx    = logical( diag(ones(1,8),0) ); 
a(indx) = 0;

Or in 1 line if you prefer,

a(logical(diag(ones(1,8),0))) = 0;

Note that when using diag(v,k) setting k=1 places v on the main diagonal, k=1 places v on the diagonal one place above the main diagonal, and so on.

Then repeat for non-main diagonals by changing k and the size of v accordingly.




回答5:


Another way to do this is using indices directly.

For an 8x8 matrix, if you want to zero out the entries in one of the diagonals at or below the main diagonal, use this:

M((n+1):9:(64-8*n))=0;

This will run down the diagonal, stopping when it reaches the lowest row. For entries above the diagonal, instead of starting at n+1, you have to finish at 64-n, like this:

M((8*n+1):9:(64-n))=0;

In both cases, n is how far from the main diagonal you are - so n=0 is the main diagonal. This can be generalised with a bit of logic:

idx=1:9:64;
M(idx((idx+8*n)<65&(idx+8*n)>0)+8*n)=0;

For n>=0, this will select the n-th diagonal above the main diagonal. Negative values will select the diagonals below the main diagonal. Generalising further, for an NxN matrix,

idx=1:(N+1):N^2;
M(idx((idx+N*n)<=N^2&(idx+N*n)>0)+N*n)=0;

With broadcasting or appropriate use of repmat (or multiplication by a ones vector), this can be adapted to handle multiple diagonals at once, although it gets messier.




回答6:


Say you have a square matrix M. If you just want to set the entire diagonal to zero, you'd do this:

M(sub2ind(size(M), [1:length(M)]',[1:length(M)]')) = 0;

If you wanted to set SOME of the diagonals to zero, say 1:5, 8:11, you can simply modify to:

M(sub2ind(size(M), [1:5, 8:11]',[1:5, 8:11]')) = 0;

Others have suggested using for loops. Don't EVER use a for loop in Matlab unless you absolutely have to. Native Matlab functions are way faster.




回答7:


Another solution, based on Glen O's answer, that can work for non square matrices as well is presented below:

%% // Example inputs
N_ROWS = 6;
N_COLS = 4;
A = randi(20,N_ROWS,N_COLS);
DIAG_TO_MODIFY = -1;
REPLACE_VEC = rand(size(diag(A,DIAG_TO_MODIFY))); %// Will error if diagonal # is invalid.

%% // Processing; can be made a function
if  -DIAG_TO_MODIFY > N_ROWS-1 || ... 
     DIAG_TO_MODIFY > N_COLS-1
    error('Invalid diagonal number.');
end

if DIAG_TO_MODIFY < 0
    firstInd = 1 - DIAG_TO_MODIFY;
elseif DIAG_TO_MODIFY > 0
    firstInd = 1 + DIAG_TO_MODIFY*N_ROWS;
else %// DIAG_TO_MODIFY == 0 
    firstInd = 1;
end
A(firstInd:N_ROWS+1:end) = REPLACE_VEC;


来源:https://stackoverflow.com/questions/13593971/how-to-access-the-diagonals-of-a-matrix-and-change-the-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!