15個の対角線がある8x8の行列があります。左上隅の「対角線1」と右下隅の「対角線15」。{9、10、11、12、13、14、15}や{5、6、7、8、9、10、11、12、13、14、15}などの特定の対角線のセットをゼロにしたい。誰か私に解決策を教えてください?
7 に答える
私はあなたが使うことができると信じています:
M = M - diag(diag(M,k),k);
ここで、kは主対角線の場合は0、下対角線の場合は負(最大-7)、上対角線の場合は正(最大7)です。
編集:私の悪い、これはあなたの選択した対角線の1つをゼロにするだけです。ゼロにしたいすべての対角線に対してこのプロセスを繰り返すことができますが、それは最適ではない可能性があります。
for k=[9 10 11 12 13 14 15]
M = M - diag(diag(M,k-length(M)),k-length(M));
end
あなたの質問を正しく理解しているかどうかはわかりません。主対角線上の要素のサブセットをゼロにしようとしていますか、それとも対角線全体をゼロにしようとしていますか?どちらの方法でも、Matlabの「diag」関数の使用を調べることができます。
主対角線上のいくつかの要素をゼロにしたい場合は、次のようなものを使用できます。
% 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番目の対角線をゼロにするのは実際には簡単です。
3番目の対角をゼロにしたい場合は、次のようにします。A = A --diag(diag(A、3)、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.]]
私があなたをフォローしている場合、ここに簡単な方法があります:
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を主対角線の1つ上の対角線上に配置するというようになります。
次に、それに応じてkとvのサイズを変更して、非主対角線について繰り返します。
これを行う別の方法は、インデックスを直接使用することです。
8x8マトリックスの場合、主対角線またはその下の対角線の1つにあるエントリをゼロにする場合は、次を使用します。
M((n+1):9:(64-8*n))=0;
これは対角線を下って実行され、最下行に到達すると停止します。対角線より上のエントリの場合、n + 1で開始する代わりに、次のように64-nで終了する必要があります。
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の適切な使用(または1のベクトルによる乗算)を使用すると、これは、厄介になりますが、一度に複数の対角線を処理するように適合させることができます。
正方行列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関数ははるかに高速です。
グレンOの回答に基づいた、非正方行列でも機能する別のソリューションを以下に示します。
%% // 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;