2016-09-19 5 views
4

私は(3、m)配列内にいくつかのデータを持っています。ブール値の行の2D配列を使用して別の2D配列をフィルタリングするにはどうすればよいですか?

私は(n、3)の形のマスクの別の配列を持っています。このマスクの行は、機能を実行する前にデータ配列に適用する必要のあるブール値のフィルタです。フィルタを適用して関数を計算するベクトル化された方法はありますか?

ここでは、関数がmean()であると仮定して、明快にするためにループを使用する例を示します。私は純粋にナンシー(リストの理解なし)を使ってこれをしたいと思います。

(明らかに、アレイのサイズは実際にははるかに大きい。)

import numpy as np 

data = np.array([ 
     [ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11] 
    ]) 

masks = np.array([ 
     [True, True, False], 
     [False, True, False], 
     [False, True, True], 
     [True, False, False], 
     [True, False, True] 
    ]) 

means = np.array([data[mask].mean(axis=0) for mask in masks]) 

# means 
array([[ 2., 3., 4., 5.], 
     [ 4., 5., 6., 7.], 
     [ 6., 7., 8., 9.], 
     [ 0., 1., 2., 3.], 
     [ 4., 5., 6., 7.]]) 
+0

投稿されたアプローチをすべて試しましたか?誰かがあなたのために働いたのですか?実際の入力設定のようなランタイム番号は何ですか? – Divakar

+0

謝罪、はい、それらを試してみました。あなたのものは具体的には手段の中で最速だったし、私が下で説明したような放送は他の機能のために働く。 – capitalistcuttle

答えて

0

という問題が​​を用いmatrix-multiplicationと容易に解決可能である、そのようなものとして、実際に効率的でなければなりません。ここに実装があります -

np.true_divide(masks.dot(data),masks.sum(1)[:,None]) 
0

これはビット原油と厄介な感じ、それはループせずに作業を行います。

二つの主要なタスクがあります。

  • ので、それはmasksでインデックスを作成することができdataを拡大 - (5,4)から(5,3,4)へ
  • は、行のグループにmeansを適用します。私が見つけられる最も近いものはnp.sum.reduceatです。

reduceatインデックス構築:

In [253]: cnt = masks.sum(axis=1) 
In [254]: cnt1=np.concatenate(([0],np.cumsum(cnt)[:-1])) 
In [255]: cnt 
Out[255]: array([2, 1, 2, 1, 2]) # True count per row 
In [256]: cnt1 
Out[256]: array([0, 2, 3, 5, 6]) # reduceat index positions 

datamaskを展開:

In [257]: mdata=data[None,...].repeat(masks.shape[0],0)[masks,:] 

add行と分割行数によりグループ毎

それが助け場合:

In [263]: mdata 
Out[263]: 
array([[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 4, 5, 6, 7], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11], 
     [ 0, 1, 2, 3], 
     [ 0, 1, 2, 3], 
     [ 8, 9, 10, 11]]) 

Aこのmdata

In [285]: data[np.where(masks)[1],:] 
Out[285]: 
array([[ 0, 1, 2, 3], 
     [ 4, 5, 6, 7], 
     [ 4, 5, 6, 7], 
     [ 4, 5, 6, 7], 
     [ 8, 9, 10, 11], 
     [ 0, 1, 2, 3], 
     [ 0, 1, 2, 3], 
     [ 8, 9, 10, 11]]) 

where(...)[1]が我々の行ですmasksにおける真の列位置、あるあるを取得する可能性がより良い方法dataから選択してください。

===========================

@capitalistcuttleも(5,3,4)アレイを作成したが、 False行をゼロにしてreduceatの必要性を回避します。そうすれば、価値に影響を与えることなくmeanまたはsumに入ることができます。これは、マスクされた配列がこのようなタスクをどのように実行するかを思い起こさせます。それらはfillで、0または1のような値を持つマスクされた値は計算に影響しません。

In [322]: data1=data[None,:,:].repeat(5,0) 
In [323]: masks1=masks[:,:,None].repeat(4,-1) 
In [324]: data1.shape, masks1.shape 
Out[324]: ((5, 3, 4), (5, 3, 4)) 

ことからマスクされた配列行います:

In [325]: madata=np.ma.MaskedArray(data1,~masks1) 
In [326]: madata 
Out[326]: 
masked_array(data = 
[[[0 1 2 3] 
    [4 5 6 7] 
    [-- -- -- --]] 

[[-- -- -- --] 
    [4 5 6 7] 
    [-- -- -- --]] 
... 
[[0 1 2 3] 
    [-- -- -- --] 
    [8 9 10 11]]], 
      mask = 
[[[False False False False] 
    [False False False False] 
    [ True True True True]] 

[[ True True True True] 
    [False False False False] 
    [ True True True True]] 
    ...], 
     fill_value = 999999) 
をその触発され

はここMaskedArrayソリューション

が(5,3,4)のサイズにdatamasksの両方を展開します

今度はmeanメソッドを使用して、0の塗りつぶしを処理し、有効な行の数を調整します。 .data属性は、通常の配列に戻って変換すること

In [327]: madata.mean(axis=1) 
Out[327]: 
masked_array(data = 
[[2.0 3.0 4.0 5.0] 
[4.0 5.0 6.0 7.0] 
[6.0 7.0 8.0 9.0] 
[0.0 1.0 2.0 3.0] 
[4.0 5.0 6.0 7.0]], 
      mask = 
[[False False False False] 
[False False False False] 
[False False False False] 
[False False False False] 
[False False False False]], 
     fill_value = 1e+20) 

このMaskedArrayアプローチは、より大きい配列を作成するため、おそらく遅くなりますが、より一般的である可能性があります。np.maまたはそのメソッドで定義されている限り、操作を使用できます。

0

ので、しばらくの間、それを再生した後、(放送のこの種の平均のために働くと思われる)の関数として、具体的:

means = (masks[:, :, np.newaxis] * data).sum(axis=1)/masks.sum(axis=1)[:, np.newaxis] 

# means 
array([[ 2., 3., 4., 5.], 
     [ 4., 5., 6., 7.], 
     [ 6., 7., 8., 9.], 
     [ 0., 1., 2., 3.], 
     [ 4., 5., 6., 7.]]) 

そして、もっと一般的に他の機能のために、あなたはどこ(このフォーマットを使用することができます())は、所望の機能を置き換えることができることを意味:

means = (masks[:, :, np.newaxis] * data).mean(axis=1) * masks.shape[1]/masks.sum(axis=1)[:, np.newaxis] 

# means 
array([[ 2., 3., 4., 5.], 
     [ 4., 5., 6., 7.], 
     [ 6., 7., 8., 9.], 
     [ 0., 1., 2., 3.], 
     [ 4., 5., 6., 7.]]) 
+0

これは私の 'tile'や' repeat'のような行を複製しますが、 'False'行をゼロにして' reduceat'を使う必要はありません。 – hpaulj

関連する問題