複数の条件が機能するNumpy


132

距離と呼ばれる距離の配列があります。2つの値の間にあるdistsを選択します。それを行うために、次のコード行を書きました。

 dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]

ただし、これは条件のみを選択します

 (np.where(dists <= r + dr))

一時変数を使用してコマンドを順番に実行すると、正常に機能します。上記のコードが機能しないのはなぜですか、どうやって機能させるのですか?

乾杯

回答:


203

特定のケースでの最良の方法は 2つの基準を1つの基準に変更することです。

dists[abs(dists - r - dr/2.) <= dr/2.]

それは、唯一のブール配列を作成し、私の意見では、それが言うので読みやすいですdistdrrr最初からではなく、関心のある領域の中心になるように再定義しますが、r = r + dr/2.)しかし、それはあなたの質問には答えません。


あなたの質問への答え:基準に合わない要素を除外しようとしているだけなら、
実際には必要ありません。wheredists

dists[(dists >= r) & (dists <= r+dr)]

ので&、あなたに要素ごとを与えますand(括弧は必要です)。

または、where何らかの理由で使用したい場合は、次のようにすることができます。

 dists[(np.where((dists >= r) & (dists <= r + dr)))]

理由:
機能しない理由np.whereは、ブール配列ではなくインデックスのリストを返すためです。and2つの数値のリストの間を取得しようとしていますが、当然、期待するTrue/ False値がありません。場合ab両方ともTrue値が、その後、a and b戻りb。のようなものを言う[0,1,2] and [2,3,4]だけであなたに与えるでしょう[2,3,4]。ここでそれは動作しています:

In [230]: dists = np.arange(0,10,.5)
In [231]: r = 5
In [232]: dr = 1

In [233]: np.where(dists >= r)
Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)

In [234]: np.where(dists <= r+dr)
Out[234]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
Out[235]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)

あなたが比較することを期待していたのは単にブール配列でした、例えば

In [236]: dists >= r
Out[236]: 
array([False, False, False, False, False, False, False, False, False,
       False,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True], dtype=bool)

In [237]: dists <= r + dr
Out[237]: 
array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True, False, False, False, False, False,
       False, False], dtype=bool)

In [238]: (dists >= r) & (dists <= r + dr)
Out[238]: 
array([False, False, False, False, False, False, False, False, False,
       False,  True,  True,  True, False, False, False, False, False,
       False, False], dtype=bool)

これnp.whereで、結合されたブール配列を呼び出すことができます。

In [239]: np.where((dists >= r) & (dists <= r + dr))
Out[239]: (array([10, 11, 12]),)

In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
Out[240]: array([ 5. ,  5.5,  6. ])

または、ファンシーインデックスを使用して、ブール配列で元の配列にインデックスを付けるだけです

In [241]: dists[(dists >= r) & (dists <= r + dr)]
Out[241]: array([ 5. ,  5.5,  6. ])

61

受け入れられた答えは問題を十分に説明しました。ただし、複数の条件を適用するためのよりNumpythonicのアプローチは、numpy論理関数を使用することです。このASEでは、以下を使用できますnp.logical_and

np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))

11

ここで指摘すべき興味深い点の1つは、この場合、ORおよびANDを使用する通常の方法も機能しますが、少し変更します。「and」の代わりに「or」の代わりに、Ampersand(&)Pipe Operator(|)を使用すれば機能します。

「and」を使用する場合:

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) and (ar<6), 'yo', ar)

Output:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Ampersand(&)を使用する場合:

ar = np.array([3,4,5,14,2,4,3,7])
np.where((ar>3) & (ar<6), 'yo', ar)

Output:
array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')

これは、pandas Dataframeの場合に複数のフィルターを適用しようとする場合も同様です。これの背後にある理由は、論理演算子とビットごとの演算子で何かを行う必要があるため、同じことをさらに理解するために、この答えまたは同様のQ / Aをスタックオーバーフローで実行することをお勧めします。

更新

かっこ内に(ar> 3)と(ar <6)を指定する必要があるのはなぜですか。まあここにあるものです。ここで何が起こっているのかを説明する前に、Pythonでの演算子の優先順位について知っておく必要があります。

BODMASの場合と同様に、Pythonも最初に実行する必要があるものを優先します。括弧内の項目が最初に実行され、次にビット演算子が機能するようになります。「(」、「)」を使用した場合と使用しない場合の両方の場合に何が起こるかを以下に示します。

ケース1:

np.where( ar>3 & ar<6, 'yo', ar)
np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)

ここに角括弧がないため、ビットごとの演算子(&)はここで混乱します。これは、論理積を取得するように要求しているのは何ですか。演算子の優先順位表で&は、<or >演算子よりも優先順位が高いためです。優先順位の低いものから優先順位の高いものまでの表を次に示します。

ここに画像の説明を入力してください

<and >演算を実行することも、論理AND演算を実行するように要求されることもありません。そのため、そのエラーが発生します。

詳細については、次のリンクをチェックしてください:演算子の優先順位

次にケース2に進みます。

ブラケットを使用すると、どうなるかがはっきりわかります。

np.where( (ar>3) & (ar<6), 'yo', ar)
np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)

TrueとFalseの2つの配列。そして、それらに対して論理AND演算を簡単に実行できます。それはあなたに与える:

np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)

そして、あなたが知っている残りの部分は、所与のケースでは、Trueの場合は常に最初の値(つまり、ここでは「yo」)を割り当て、Falseの場合は他の値(つまり、ここでは元の値を維持)を割り当てます。

それで全部です。クエリをうまく説明できれば幸いです。


1
なぜあなたは()周りに置く必要が(ar>3)あり(ar>6)ますか?
RTrain3k

それは本当に良い質問です。地球上で何が必要なのかを自分で考えなければならないのは、とても良い質問です。だから私はそうしました、同僚にも尋ねました、そして今、私はあなたに解決策を持っているamdについて話し合いました。それをUPDATEとして答えに入れます。それは本当にシンプルですが、本当に理解するのは難しいことです。
アミットアモラ

アップデートRTrain3kをチェックアウトしてください、私はあなたの質問に答えました。
アミットアモラ

5

np.vectorizeはそのような仕事に使うのが好きです。以下を検討してください。

>>> # function which returns True when constraints are satisfied.
>>> func = lambda d: d >= r and d<= (r+dr) 
>>>
>>> # Apply constraints element-wise to the dists array.
>>> result = np.vectorize(func)(dists) 
>>>
>>> result = np.where(result) # Get output.

np.argwhere代わりにnp.where明確な出力のために使用することもできます。しかし、それはあなたの呼び出しです:)

それが役に立てば幸い。



2

これはうまくいくはずです:

dists[((dists >= r) & (dists <= r+dr))]

最もエレガントな方法~~


2

試してください:

import numpy as np
dist = np.array([1,2,3,4,5])
r = 2
dr = 3
np.where(np.logical_and(dist> r, dist<=r+dr))

出力:(array([2、3])、)

詳細については、ロジック関数を参照してください。


0

私はこの簡単な例を解決しました

import numpy as np

ar = np.array([3,4,5,14,2,4,3,7])

print [X for X in list(ar) if (X >= 3 and X <= 6)]

>>> 
[3, 4, 5, 4, 3]

6
この場合、反復する必要はありません。NumPyにはブールインデックスがあります。
M456 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.