【问题标题】:How to access the diagonals of a matrix and change the value?如何访问矩阵的对角线并更改值?
【发布时间】:2012-11-27 22:04:16
【问题描述】:

我有 8x8 矩阵,其中有 15 条对角线。左上角“对角线 1”和下 右上角“对角线 15”。我想将特定的对角线集归零,例如 {9, 10, 11, 12, 13, 14, 15} 或 {5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} .哪位大神给个解决办法?

【问题讨论】:

  • 你有一个 8x8 矩阵,对角线上有 15 个元素???你确定?
  • 你在使用 Python 和 Numpy 吗?
  • 8x8 矩阵,15 条对角线@jerad

标签: matlab matrix octave


【解决方案1】:

我相信你可以使用:

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

其中 k 为主对角线为 0,下对角线为负数(最多 -7),上对角线为正数(最多 7 个)。

编辑:我的错,这只会将您选择的对角线之一归零。您可以对要归零的所有对角线重复该过程,但这可能不是最佳的:

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

【讨论】:

  • 在循环外打印后得到相同的矩阵。当我将 disp(M) 放入循环中时,我会在每次迭代中看到它会将 1 个对角线归零,并且在下一次迭代中它会回到之前的值。
  • 这很奇怪,我刚刚测试了这段代码,它工作正常。你在循环中做其他事情吗?你能给出你运行的代码吗?
  • 这是目前的代码 - M = imread('image file'); [i j] = 网格网格(1:8:256); %// 索引格 idx = num2cell([ i(:) , j(:) ],2); %// 单元格版本 matr = cellfun(@(i) M(i(1):i(1)+7,i(2):i(2)+7), idx, 'UniformOutput',false); %// 块 disp(matr{2});对于 k=[9 10 11 12 13 14 15] A = matr{2} - diag(diag(matr{2},k-length(matr{2})),k-length(matr{2}));显示(一);结束显示(A);
  • 我解决了这个问题。谢谢。你的技术从左下角归零而不是从左上角归零,这就是我想要的左上角。我必须对您的代码进行哪些更改? @nbeuchat
  • 你可以试试这个:M = M - diag(diag(M,length(M)-k),length(M)-k);
【解决方案2】:

我不确定我是否正确理解了您的问题。您是想将主对角线上的某些元素子集归零,还是试图将整个对角线归零?无论哪种方式,您都可以考虑使用 Matlab 的“诊断”功能。

如果你只想将主对角线上的一些元素归零,你可以使用类似的东西:

% 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

但是使用 for 循环会更容易:

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

清零 A 的第 n 个对角线实际上更容易:

假设您想将第三条对角线归零,您可以: A = A - diag(diag(A,3),3);

【讨论】:

  • 我想将整个对角线归零。基本上我想将一组对角线归零,例如 8x8 矩阵的 {9, 10, 11, 12, 13, 14, 15} 对角线。我尝试使用 A = A - diag(diag(A,3),3);当我想用于第 9 个对角线时 A = A-diag(diag(A,9),9);它显示错误“矩阵尺寸必须一致”。
  • 如果您的矩阵为 8 x 8,则索引将从 -7 变为 7(主对角线下方的对角线为负数,上方为正数,主对角线索引为 0)。这就是 nbeuchat 的回答。
  • 我明白了。谢谢。但问题是解决方案从左下角而不是从左上角归零。我的意思是我需要左上角“对角线 1”和右下角“对角线 15”。
  • “左上角对角线 1”和“右下角对角线 15”应该是什么意思?我认为没有人遵循该术语。
  • 如果您试图将“反方向”(从左下角到右上角)的对角线归零,您可以使用“flipud”函数:A = flipud(flipud (A) - 诊断(诊断(翻转(A),3),3))。同样,编号从 -7 变为 7。
【解决方案3】:

我认为我的对角线方向相反,但你应该明白。

Python 代码:

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

这是截断的输出:

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】:

    如果我跟着你,这里有一个简单的方法:

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

    如果您愿意,也可以在 1 行中,

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

    请注意,当使用 diag(v,k) 设置 k=1 时,将 v 放置在主对角线上,k=1 将 v 放置在对角线上,主对角线上方一个位置,依此类推。

    然后通过相应地改变 k 和 v 的大小来重复非主对角线。

    【讨论】:

      【解决方案5】:

      另一种方法是直接使用索引。

      对于 8x8 矩阵,如果要将主对角线处或下方的对角线之一中的条目归零,请使用以下命令:

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

      这将沿着对角线运行,当它到达最低行时停止。对于对角线以上的条目,您必须在 64-n 处结束,而不是从 n+1 开始,如下所示:

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

      在这两种情况下,n 都是您离主对角线的距离 - 所以 n=0 是主对角线。这可以用一点逻辑概括:

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

      对于 n>=0,这将选择主对角线上方的第 n 个对角线。负值将选择主对角线下方的对角线。进一步推广,对于 NxN 矩阵,

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

      通过广播或适当使用 repmat(或乘以一个向量),这可以适应一次处理多个对角线,尽管它会变得更加混乱。

      【讨论】:

        【解决方案6】:

        假设您有一个方阵 M。如果您只想将整个对角线设置为零,您可以这样做:

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

        如果您想将某些对角线设置为零,例如 1:5、8:11,您可以简单地修改为:

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

        其他人建议使用 for 循环。除非绝对必要,否则永远不要在 Matlab 中使用 for 循环。原生 Matlab 函数要快得多。

        【讨论】:

          【解决方案7】:

          基于Glen O's answer 的另一种解决方案也适用于非方阵,如下所示:

          %% // 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;
          

          【讨论】:

            猜你喜欢
            • 2019-08-18
            • 1970-01-01
            • 2018-01-18
            • 2012-04-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多