2012-03-31 23 views
27

numpyで行列の対角線の値を変更するにはどうすればよいですか?numpyで行列の対角の値を変更する

Numpy modify ndarray diagonalを調べましたが、numpy v 1.3.0では実装されていません。

たちはnp.array Xを持っていると私は0サイズはN×N行列でnは

+1

どのnumpyのバージョンを使用していますか? 'np.diag_indices_from'がv1.4で追加されました – JoshAdel

+0

yep、あなたは正しいです、私は現在python v 1.3.0を使用しています – pacodelumberg

+0

@LangerHansIslandsうまくいけば、python 1.3ではなく、numpy 1.3を意味します。 。:p) – Dougal

答えて

36

numpy.fill_diagonalを試しましたか?次のanswerおよびdiscussionを参照してください。または(現在は壊れたが)ドキュメントから次

http://docs.scipy.org/doc/numpy/reference/generated/numpy.fill_diagonal.html

+0

ありがとうございます@JoshAdel – Mellkor

+0

+1これはnumpyでこれを行う適切な方法です。組み込み関数は、2つのforループを使用して一度に1つの要素を反復処理するよりも常に望ましいです。 – JoshAdel

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

に対角線のすべての値を設定したいと言うことができます。

+3

または 'n = len(replacement_list);行列[:n、:n] =置換リスト。これはPythonの代わりにC言語でループを行うので、はるかに高速になります。 – Dougal

+0

@Dougal:恐ろしい、私はそれを知らなかった。回答として投稿できますか? –

+0

確かに、[ちょっと](http://stackoverflow.com/a/9959707/344821)。 – Dougal

12

あなたがdiag_indices_fromまたは(定数に対角を設定するright wayfill_diagonalを持っていませんnumpyののバージョンを使用している場合は、あなたは、配列のスライスとかなり簡単にこれを行うことができます。

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

ループはCで発生し、潜在的にベクトル化されるので、これは、Pythonで明示的なループよりもはるかに高速です。

これは、一定値(例えば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呼び出しがzipはイテレータを返すのPython 3にのみ必要です)

+0

将来の読者のために、 'mat [:n、:n] = 0'は対角要素だけでなく、配列/ matrix_全体を0に設定します。 'ジップ'バージョンは確かにダイアグを行います。 – gorlum0

+0

@ gorlum0おっとり - それを指摘してくれてありがとう。私はちょうどそれを修正するために編集しました( 'zip'は実際そこには必要ありません)。 – Dougal

+0

涼しい、むき出しの「範囲」。この暗黙のことは知るのが難しいです。 – gorlum0

9

ここでこれを行うための別の良い方法です。 i番目の対角の使用については

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

:i番目の副対角の使用については

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

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以降では、配列の 'diagonal'メソッドはコピーではなくビューを返すように計画されていました。 この変更はまだ行われていませんが、いつの間にかビューを得るためのこのトリックはもはや必要なくなります。 http://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.diagonal.html

+0

ニースとハッキー、私はそれが好き!注意しておけば、['np.fill_diagonal's](http://docs.scipy.org/doc/numpy/reference/generated/numpy.fill_diagonal.html)に記述されている' wrap = True'の動作が得られると思います。 )。おそらく、スライスに適切な停止値を追加することで解決できます。 – Jaime

+0

ありがとう、良いキャッチ。私はそれを修正するためにそれを編集しました。 – IanH

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 
関連する問題