2016-04-07 6 views
0

行列の中で最も頻繁に使用される要素は、隣接値とそれ自体に基づいて計算する必要があります。私はgeneric_filter関数を見つけました。だからここに私は2次元配列3d配列のndimage.generic_function

arr = np.array([ 
    [1, 2, 4], 
    [5, 6, 7], 
    [2, 4, 4] 
]) 

def most_frequent(arr): 
    def most_frequent(val): 
     return Counter(val).most_common(1)[0][0] 

    footprint = [[1, 1, 1], [1, 1, 1], [1, 1, 1]] 
    return ndimage.generic_filter(arr, most_frequent, footprint=footprint, mode='constant') 

print most_frequent(arr) 

のためにこれを行うことができる方法である。このエッジ上の要素を無視してくれ

[[0 0 0] 
[0 4 0] 
[0 0 0]] 

を返します。あなたが見るように、中間要素は4です。これは、これが隣人と値の中で最も頻繁に存在する要素なのでです。


大きな問題は、私が3dマトリクスに対して同じことをする必要があることです。したがって、この

arr = np.array([ 
    [[1, 1], [2, 2], [4, 4]], 
    [[5, 5], [6, 6], [7, 7]], 
    [[2, 2], [4, 4], [4, 4]] 
]) 

のような行列のために、私は途中でどこでも[0, 0][4, 4]を得ることを期待します。これは、RuntimeError('filter footprint array has incorrect shape.')で失敗します。

CVAL:スカラー、オプションの値のモードが 「定数」であれば、入力の過去のエッジを埋めるために、私はドキュメントが言うので、私はgeneric_filterここに使用することができます疑問を持っているより悪い事。

どうすれば問題を解決できますか?

+0

3D入力配列には整数だけが含まれていますか? – Divakar

+0

もう1つの質問 - このようなフィルタをentir e '(3,3,2)'だけではなく、任意の長さの3D配列ができますか? – Divakar

答えて

1

完全にベクトル化されたソリューションです。

まずメイク平坦化地域:

(n,m,_)=M.shape 
(sn,sm,s2)=M.strides 
newshape=(n-2,m-2,9,2) 
newstrides=(sn,sm,2*s2,s2) 
neighborhoods=np.lib.stride_tricks.as_strided(M,newshape,newstrides) 
""" 
array([[[[1, 1], 
     [2, 2], 
     [4, 1], 
     [1, 1], 
     [5, 5], 
     [6, 6], 
     [7, 7], 
     [2, 3], 
     [2, 2]], 

     [[2, 2], 
     [4, 1], 
     [1, 1], 
     [5, 5], 
     [6, 6], 
     [7, 7], 
     [2, 3], 
     [2, 2], 
     [4, 1]]]]) 
    """ 

はその後、1次元配列を扱うnp.uniqueを使用するには、2つのコンポーネントをパックする必要があります。

packed_neighborhoods=np.ascontiguousarray(neighborhoods).view(int64) 
In [5]: packed_neighborhoods.shape 
Out[5]: (1, 2, 9, 1) 

今、私たちはnp.uniqueに基づいて、1次元配列を取り、最も頻繁にindiceを見つける機能を定義します:

def mostfreq(arr): 
    _,index,counts=unique(arr, return_index=True, return_counts=True) 
    return index[counts.argmax()] 

M.dtypeはint32ですと仮定すると、あなたは、ビューでそれを行うことができます良い軸でそれを適用してください:

ind2=apply_along_axis(mostfreq,2,packed_neighborhoods).squeeze() 

そして、他のインデックスを含む結果があります。

ind0,ind1=indices(neighborhoods.shape[:2]) 
print(neighborhoods[ind0,ind1,ind2]) 
""" 
[[[1 1] 
    [4 1]]] 
""" 

しかし、あなたのソリューションは、現時点で同じ性能を持っています。(私はこれを達成する方法を発見した

+0

うわー、それは動作するように見えます。私は調査に時間がかかるでしょう。このようにしてフットプリントを変更するというアイデアはどう思いますか? –

+0

'フィルタフットプリントアレイの形状が正しくありません。' 。データndimに合わせて1つのディメンションを追加する必要があります。編集されました。 –

+0

そこに問題があるようです。たとえば、この配列arr = 'np.array([ [[1,1]、[2,2]、[4,1]、[1,1]]の場合、 [[5,5]、[6 、[2,3]、[7,7]、[2,3]]、 [[2,2]、[4,1]、[4,4]、[2,3]] ]結果は '[2 1]'ですが、そのような要素は配列にも存在しません。 –

0

一つの方法は、まだ良い解決策を探して

def most_frequent(M): 
    x, y, _ = arr.shape 
    res = np.zeros((x - 2, y - 2, 2)) 
    for i in xrange(1, x - 1): 
     for j in xrange(1, y - 1): 
      neighbors = [M[i - 1, j - 1], M[i - 1, j], M[i - 1, j + 1], M[i, j - 1], M[i, j], M[i, j + 1], M[i + 1, j - 1], M[i + 1, j], M[i + 1, j + 1]] 
      res[i - 1, j - 1] = Counter([tuple(_) for _ in neighbors]).most_common(1)[0][0] 

    return res 

ような何かを行うことです。 (私の2つのループを含まないもの)

+0

'M 'は入力3D配列と同じですか? – Divakar

+0

@Divakarはい、そうです –