2017-12-17 15 views
0

Nypy配列内の任意の[i、j]または[i、j、k]インデックスに隣接するすべてのセルに同じ番号(int/float)を追加すると効果的な方法がありますか?ちょうど正しいスライスコマンドを見つけることができないようです。N-Dim Sparse Numpy Arrayの行/列インデックスに隣接するすべてのセルに数値を簡単に追加できますか?

import numpy as np 
arr = np.zeros((5,5)) 
arr[0,0] = 2 
arr[2,2] = 1 
arr 

(手動で所望の出力を表示するためにコード化された)を以下に示す効果を達成するために探している戻り

Out [1]: array([[ 2., 0., 0., 0., 0.], 
       [ 0., 0., 0., 0., 0.], 
       [ 0., 0., 1., 0., 0.], 
       [ 0., 0., 0., 0., 0.], 
       [ 0., 0., 0., 0., 0.]]) 

が、直接セルの内容またはインデックス番号を知らなくても、それらが非ゼロである以外、配列内のすべての要素をループする必要はありません。 0パディング配列を使用した作業

# Add 2 around [0,0] 
arr[0:2, 0:2] += 2 
arr[0,0] -= 2 

# Add 1 around [2,2] 
arr[1:4,1:4] += 1 
arr[2,2] -= 1 
arr 

Out [2]: array([[ 2., 2., 0., 0., 0.], 
       [ 2., 3., 1., 1., 0.], 
       [ 0., 1., 1., 1., 0.], 
       [ 0., 1., 1., 1., 0.], 
       [ 0., 0., 0., 0., 0.]]) 
+0

ConwayのLIfeのためにこのコードで行われた複数のオフセットの合計は、おそらくあなたが得るほど速くなります:https://stackoverflow.com/questions/47648106/python-numpy-slicing-indepth-explnation私の直感は、配列が非常にまばらでない限り、あなたの選択肢が遅くなるということです。どちらの方法でも境界を処理すると複雑になります。 – hpaulj

+0

すべての非ゼロ点を一度に追加するには、 '+ ='のバッファ化されていないバージョンである 'add.at'を使う必要があります。さもなければ、 'arr [1,1]'に対して '2 + 1'を得ることはありません。 'add.at'はバッファされたコードよりも遅く、スライスを使用しません。 – hpaulj

+0

あなたの実際のユースケースのスパースタイの尺度は何ですか?ゼロ以外の割合? – Divakar

答えて

1
In [85]: arr = np.zeros((5,5)) 
    ...: arr[0,0] = 2 
    ...: arr[2,2] = 1 
    ...: 
In [86]: arr 
Out[86]: 
array([[ 2., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 1., 0., 0.], 
     [ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

容易にする必要があります:

最初の繰り返し、あなたのアイデアを試して Python: Numpy slicing indepth explnation

In [89]: N = np.zeros_like(arr1) 
In [90]: Z=arr1 
In [91]:  N[1:, 1:] += Z[:-1, :-1] 
    ...:  N[1:, :-1] += Z[:-1, 1:] 
    ...:  N[:-1, 1:] += Z[1:, :-1] 
    ...:  N[:-1, :-1] += Z[1:, 1:] 
    ...:  N[:-1, :] += Z[1:, :] 
    ...:  N[1:, :] += Z[:-1, :] 
    ...:  N[:, :-1] += Z[:, 1:] 
    ...:  N[:, 1:] += Z[:, :-1] 

In [93]: N += Z 
In [94]: N 
Out[94]: 
array([[ 2., 2., 2., 0., 0., 0., 0.], 
     [ 2., 2., 2., 0., 0., 0., 0.], 
     [ 2., 2., 3., 1., 1., 0., 0.], 
     [ 0., 0., 1., 1., 1., 0., 0.], 
     [ 0., 0., 1., 1., 1., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0., 0., 0.]]) 
In [95]: N[1:-1, 1:-1] 
Out[95]: 
array([[ 2., 2., 0., 0., 0.], 
     [ 2., 3., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

を適応さ

In [87]: arr1 = np.zeros((arr.shape[0]+2, arr.shape[1]+2),arr.dtype) 
In [88]: arr1[1:-1,1:-1]=arr 

....

非ゼロ:それらの

In [124]: idx = np.argwhere(arr1) 
In [125]: idx 
Out[125]: 
array([[1, 1], 
     [3, 3]], dtype=int32) 

反復:

In [126]: N1 = np.zeros_like(arr1) 
In [127]: for i in idx: 
    ...:  slc = (slice(i[0]-1,i[0]+2), slice(i[1]-1,i[1]+2)) 
    ...:  N1[slc] += arr1[tuple(i)] 
    ...: 
In [128]: N1[1:-1,1:-1] 
Out[128]: 
array([[ 2., 2., 0., 0., 0.], 
     [ 2., 3., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

同じ繰り返しが、np.add.atと:

In [132]: N1 = np.zeros_like(arr1) 
In [133]: for i in idx: 
    ...:  slc = (slice(i[0]-1,i[0]+2), slice(i[1]-1,i[1]+2)) 
    ...:  np.add.at(N1, slc, arr1[tuple(i)]) 

次のステップは、それらのslc 1に全体を統合することであろう、そうnp.add.atが可能一度行った。

In [143]: for i in idx: 
    ...:  slc = (slice(i[0]-1,i[0]+2), slice(i[1]-1,i[1]+2)) 
    ...:  ii = np.ix_(np.r_[slc[0]],np.r_[slc[1]]) 
    ...:  np.add.at(N1,ii, arr1[tuple(i)]) 
    ...:  print(ii) 
    ...:  
    ...: 
(array([[0], 
     [1], 
     [2]]), array([[0, 1, 2]])) 
(array([[2], 
     [3], 
     [4]]), array([[2, 3, 4]])) 

(継続する)私は[0,1,2,2,3,4]などを作るために、これらを連結でき考えていた。しかし、それは仕事に行くのではないです。その第一歩はnp.ix_でスライスを拡大することです。 mgrid配列を生成し、それらを連結する必要があります。

In [159]: slc=[np.mgrid[(slice(i[0]-1,i[0]+2), slice(i[1]-1,i[1]+2))] for i in idx] 
In [160]: slc = tuple(np.hstack(slc)) 
In [161]: N2 = np.zeros_like(arr1) 
In [162]: np.add.at(N2, slc,1) 
In [163]: N2[1:-1,1:-1] 
Out[163]: 
array([[ 1., 1., 0., 0., 0.], 
     [ 1., 2., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 1., 1., 1., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

これは近いです。対応するarrの値ではなく、各ポイントに1を加えています。私はそれらのポイントを正しい形でブロードキャストする必要があります。

これはまだゼロ以外の点を反復していますが、ブロードキャストされた追加でそのidx配列を生成することは想像できます。

私はこれらを追加する必要があります。そのような中

In [182]: slc1 = np.mgrid[slice(-1,2), slice(-1,2)] 
In [183]: slc1 
Out[183]: 
array([[[-1, -1, -1], 
     [ 0, 0, 0], 
     [ 1, 1, 1]], 

     [[-1, 0, 1], 
     [-1, 0, 1], 
     [-1, 0, 1]]]) 
In [177]: idx 
Out[177]: 
array([[1, 1], 
     [3, 3]], dtype=int32) 

を道として生成するよう:

In [179]: slc=[np.mgrid[(slice(i[0]-1,i[0]+2), slice(i[1]-1,i[1]+2))] for i in idx] 
In [180]: slc=np.hstack(slc) # np.concatenate(slc, axis=1) 
In [181]: slc 
Out[181]: 
array([[[0, 0, 0], 
     [1, 1, 1], 
     [2, 2, 2], 
     [2, 2, 2], 
     [3, 3, 3], 
     [4, 4, 4]], 

     [[0, 1, 2], 
     [0, 1, 2], 
     [0, 1, 2], 
     [2, 3, 4], 
     [2, 3, 4], 
     [2, 3, 4]]]) 

これはそれをしない(しかし、私はより直接的に行うことができますか?)一致する形状に非ゼロ値を複製

In [228]: slc2 = idx.T[:,:,None,None]+slc1[:,None,:,:] 
In [229]: np.concatenate(list(slc2.transpose(1,0,2,3)),1) 
Out[229]: 
array([[[0, 0, 0], 
     [1, 1, 1], 
     [2, 2, 2], 
     [2, 2, 2], 
     [3, 3, 3], 
     [4, 4, 4]], 

     [[0, 1, 2], 
     [0, 1, 2], 
     [0, 1, 2], 
     [2, 3, 4], 
     [2, 3, 4], 
     [2, 3, 4]]]) 

:最後の反復はまた、(ため)放送の動作なし

In [288]: pts = arr1[tuple(idx.T)] 
In [289]: pts 
Out[289]: array([ 2., 1.]) 
In [290]: pts1 = pts.repeat(3)[:,None].repeat(3,axis=1) 
In [291]: pts1 
Out[291]: 
array([[ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 2., 2., 2.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.], 
     [ 1., 1., 1.]]) 
In [292]: np.add.at(N2,tuple(Out[229]), pts1) 

pts1 = pts.repeat(3)[:,None]

これは、いくつかの関数にパックされ、いくつかの現実的なサイズの配列でタイムアウトすることができます。

+0

本当に深い解決に感謝します。それでもまだ作業していますが、インデックス作成のソリューションでさえ、私が試した2つの例を見ても分かります – StuckOnDiffyQ

関連する問題