MATLABでは、特定の条件を満たす値のインデックスを簡単に見つけることができます。
>> a = [1,2,3,1,2,3,1,2,3];
>> find(a > 2) % find the indecies where this condition is true
[3, 6, 9] % (MATLAB uses 1-based indexing)
>> a(find(a > 2)) % get the values at those locations
[3, 3, 3]
Pythonでこれを行う最良の方法は何でしょうか?
これまでのところ、私は次のことを思いつきました。値を取得するには:
>>> a = [1,2,3,1,2,3,1,2,3]
>>> [val for val in a if val > 2]
[3, 3, 3]
しかし、これらの各値のインデックスが必要な場合は、もう少し複雑です。
>>> a = [1,2,3,1,2,3,1,2,3]
>>> inds = [i for (i, val) in enumerate(a) if val > 2]
>>> inds
[2, 5, 8]
>>> [val for (i, val) in enumerate(a) if i in inds]
[3, 3, 3]
Pythonでこれを行うより良い方法はありますか、特に( 'val> 2'だけでなく)任意の条件に対してですか?
NumPyでMATLAB 'find'と同等の関数を見つけましたが、現在これらのライブラリにアクセスできません。
リスト内包表記の条件部分で使用される呼び出し可能なパラメーターを取る関数を作成できます。次に、 lambda または他の関数オブジェクトを使用して、任意の条件を渡すことができます。
def indices(a, func):
return [i for (i, val) in enumerate(a) if func(val)]
a = [1, 2, 3, 1, 2, 3, 1, 2, 3]
inds = indices(a, lambda x: x > 2)
>>> inds
[2, 5, 8]
Numpyをすべてロードする必要なく、Matlabの例に少し近づいています。
numpyにはwhere
があります:
>> import numpy as np
>> x = np.random.randint(0, 20, 10)
>> x
array([14, 13, 1, 15, 8, 0, 17, 11, 19, 13])
>> np.where(x > 10)
(array([0, 1, 3, 6, 7, 8, 9], dtype=int64),)
または、numpyの非ゼロ関数を使用します。
import numpy as np
a = np.array([1,2,3,4,5])
inds = np.nonzero(a>2)
a[inds]
array([3, 4, 5])
なぜこれを使用しないのですか:
[i for i in range(len(a)) if a[i] > 2]
または、任意の条件の場合、条件に関数f
を定義し、以下を実行します。
[i for i in range(len(a)) if f(a[i])]
このアプリケーションでより一般的に使用されるnumpy
ルーチンは numpy.where()
;です。ただし、 numpy.nonzero()
と同じように動作すると思います。
import numpy
a = numpy.array([1,2,3,4,5])
inds = numpy.where(a>2)
値を取得するには、インデックスを保存し、インデックスとともにスライスします。
a[inds]
または、オプションのパラメーターとして配列を渡すことができます。
numpy.where(a>2, a)
または複数の配列:
b = numpy.array([11,22,33,44,55])
numpy.where(a>2, a, b)
私はこの正確なことを行うための高速な方法を見つけようとしてきましたが、ここに私がつまずいたものがあります(高速ベクトル比較のためにnumpyを使用しています):
a_bool = numpy.array(a) > 2
inds = [i for (i, val) in enumerate(a_bool) if val]
これは次の場合よりもはるかに高速であることがわかります。
inds = [i for (i, val) in enumerate(a) if val > 2]
Pythonは、numpy配列で行うと比較が速くなり、および/または比較ではなく真理をチェックするだけでリスト内包表記を行うと速くなります。
編集:
私は自分のコードを再検討していましたが、1行でこれを行う可能性のあるメモリ集約度が低く、少し速く、超簡潔な方法に出会いました。
inds = np.arange( len(a) )[ a < 2 ]
任意の条件で値を取得するには、ラムダ関数でfilter()
を使用できます。
_>>> a = [1,2,3,1,2,3,1,2,3]
>>> filter(lambda x: x > 2, a)
[3, 3, 3]
_
インデックスを取得する1つの方法は、enumerate()
を使用して、インデックスと値の両方を含むタプルを作成し、それをフィルタリングすることです。
_>>> a = [1,2,3,1,2,3,1,2,3]
>>> aind = Tuple(enumerate(a))
>>> print aind
((0, 1), (1, 2), (2, 3), (3, 1), (4, 2), (5, 3), (6, 1), (7, 2), (8, 3))
>>> filter(lambda x: x[1] > 2, aind)
((2, 3), (5, 3), (8, 3))
_
私は1つの迅速かつ簡単な代替品を見つけたかもしれないと思います。ところで、np.where()関数は、どういうわけか迷惑なゼロ要素の行を含むという意味で、あまり満足のいくものではないと感じました。
import matplotlib.mlab as mlab
a = np.random.randn(1,5)
print a
>> [[ 1.36406736 1.45217257 -0.06896245 0.98429727 -0.59281957]]
idx = mlab.find(a<0)
print idx
type(idx)
>> [2 4]
>> np.ndarray
ベスト、ダ
Matlabの検索コードには2つの引数があります。 Johnのコードは最初の引数を説明しますが、2番目の引数は説明しません。たとえば、インデックスのどこで条件が満たされているかを知りたい場合、Mtlabの関数は次のようになります。
find(x>2,1)
Johnのコードを使用して行う必要があるのは、indexs関数の最後に[x]を追加することだけです。ここで、xは探しているインデックス番号です。
def indices(a, func):
return [i for (i, val) in enumerate(a) if func(val)]
a = [1, 2, 3, 1, 2, 3, 1, 2, 3]
inds = indices(a, lambda x: x > 2)[0] #[0] being the 2nd matlab argument
>>> 2を返し、最初のインデックスは2を超えます。