配列内の何かの最初のインデックスを返すNumPy関数はありますか?
質問
Pythonリストが何かの最初のインデックスを返すメソッドがあることは知っています:
>>> l = [1, 2, 3]
>>> l.index(2)
1
NumPy配列にはそのようなものがありますか?
解決
はい、NumPy配列 array
と、検索する値 item
を指定した場合の答えは次のとおりです。
itemindex = numpy.where(array==item)
結果は、最初にすべての行インデックス、次にすべての列インデックスを持つタプルです。
たとえば、配列が2次元であり、2つの場所にアイテムが含まれている場合
array[itemindex[0][0]][itemindex[1][0]]
アイテムと同等になるため、
array[itemindex[0][1]][itemindex[1][1]]
他のヒント
最初に出現する 1つの値のみのインデックスが必要な場合は、 nonzero
(または where
を使用できます。この場合も同じです):
>>> t = array([1, 1, 1, 2, 2, 3, 8, 3, 8, 8])
>>> nonzero(t == 8)
(array([6, 8, 9]),)
>>> nonzero(t == 8)[0][0]
6
各多数の値の最初のインデックスが必要な場合、明らかに上記と同じことを繰り返し実行できますが、より高速なトリックがあります。以下は、各サブシーケンスの最初の要素のインデックスを見つけます:
>>> nonzero(r_[1, diff(t)[:-1]])
(array([0, 3, 5, 6, 7, 8]),)
3の両方のサブシーケンスと8の両方のサブシーケンスの始まりを見つけることに注意してください:
[ 1 、1、1、 2 、2、 3 、 8 、 3 、 8 、8]
つまり、各値の最初の出現を見つけることとは少し異なります。プログラムでは、 t
のソートされたバージョンを使用して、必要なものを取得できる場合があります。
>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)
NumPy配列を空中のリストに変換し、そのインデックスを取得することもできます。たとえば、
l = [1,2,3,4,5] # Python list
a = numpy.array(l) # NumPy array
i = a.tolist().index(2) # i will return index of 2
print i
1が印刷されます。
これを他の何かへのインデックスとして使用する場合、配列がブロードキャスト可能であればブール型インデックスを使用できます。明示的なインデックスは必要ありません。これを行うための絶対的に最も簡単な方法は、真理値に基づいて単純にインデックスを付けることです。
other_array[first_array == item]
任意のブール演算が機能します:
a = numpy.arange(100)
other_array[first_array > 50]
非ゼロのメソッドもブール値を取ります:
index = numpy.nonzero(first_array == item)[0][0]
2つのゼロは、インデックスのタプル(first_arrayが1Dであると仮定)、およびインデックスの配列の最初のアイテム用です。
非常にパフォーマンスの良い便利な numbaでタグ付けされた質問を表示 np.ndenumerate
<に基づく代替/ a>最初のインデックスを見つける:
from numba import njit
import numpy as np
@njit
def index(array, item):
for idx, val in np.ndenumerate(array):
if val == item:
return idx
# If no item was found return None, other return types might be a problem due to
# numbas type inference.
これは非常に高速で、多次元配列で自然に処理します:
>>> arr1 = np.ones((100, 100, 100))
>>> arr1[2, 2, 2] = 2
>>> index(arr1, 2)
(2, 2, 2)
>>> arr2 = np.ones(20)
>>> arr2[5] = 2
>>> index(arr2, 2)
(5,)
これは、 np.where
または np.nonzero
を使用するアプローチよりもはるかに高速になります(操作を短絡するため)。
ただし、 np.argwhere
は多次元配列を優雅に処理することもできます(手動でタプルにキャストする必要があります ショートサーキットではありません)が、一致しない場合は失敗します見つかった:
>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)
l.index(x)
は、 i がリスト内で最初に出現するxのインデックスになるように、最小の i を返します。
Pythonの index()
関数は、最初の一致が見つかった後に停止するように実装されているため、最適な平均パフォーマンスが得られると安全に想定できます。
NumPy配列で最初に一致した後に停止する要素を見つけるには、イテレーター( ndenumerate )。
In [67]: l=range(100)
In [68]: l.index(2)
Out[68]: 2
NumPy配列:
In [69]: a = np.arange(100)
In [70]: next((idx for idx, val in np.ndenumerate(a) if val==2))
Out[70]: (2L,)
要素が見つからない場合、 index()
と next
の両方のメソッドがエラーを返すことに注意してください。 next
を使用すると、2番目の引数を使用して、要素が見つからない場合に特別な値を返すことができます。例:
In [77]: next((idx for idx, val in np.ndenumerate(a) if val==400),None)
NumPyには、配列内の要素を見つけるために使用できる他の関数( argmax
、 where
、および nonzero
)があります。しかし、それらはすべて、配列全体を検索して all の出現を探すという欠点があるため、最初の要素を見つけるために最適化されていません。また、 where
および nonzero
は配列を返すため、インデックスを取得するには最初の要素を選択する必要があります。
In [71]: np.argmax(a==2)
Out[71]: 2
In [72]: np.where(a==2)
Out[72]: (array([2], dtype=int64),)
In [73]: np.nonzero(a==2)
Out[73]: (array([2], dtype=int64),)
時間の比較
大規模な配列の場合、イテレータを使用したソリューションの方が、検索アイテムが配列の先頭にある場合に高速になります (IPythonシェルで%timeit
を使用) :
In [285]: a = np.arange(100000)
In [286]: %timeit next((idx for idx, val in np.ndenumerate(a) if val==0))
100000 loops, best of 3: 17.6 µs per loop
In [287]: %timeit np.argmax(a==0)
1000 loops, best of 3: 254 µs per loop
In [288]: %timeit np.where(a==0)[0][0]
1000 loops, best of 3: 314 µs per loop
これは未解決の NumPy GitHubの問題です。
任意の基準でインデックスを作成するには、次のようにします:
In [1]: from numpy import *
In [2]: x = arange(125).reshape((5,5,5))
In [3]: y = indices(x.shape)
In [4]: locs = y[:,x >= 120] # put whatever you want in place of x >= 120
In [5]: pts = hsplit(locs, len(locs[0]))
In [6]: for pt in pts:
.....: print(', '.join(str(p[0]) for p in pt))
4, 4, 0
4, 4, 1
4, 4, 2
4, 4, 3
4, 4, 4
そして、list.index()が行うことを行うクイック関数がありますが、例外が見つからない場合は例外を発生させません。注意してください-これはおそらく大きな配列では非常に遅いです。メソッドとして使用したい場合は、おそらくこれを配列にモンキーパッチすることができます。
def ndindex(ndarray, item):
if len(ndarray.shape) == 1:
try:
return [ndarray.tolist().index(item)]
except:
pass
else:
for i, subarray in enumerate(ndarray):
try:
return [i] + ndindex(subarray, item)
except:
pass
In [1]: ndindex(x, 103)
Out[1]: [4, 0, 3]
1D配列の場合、 np.flatnonzero(array == value)[0]
をお勧めします。これは、 np.nonzero(array == value)[0 ] [0]
および np.where(array == value)[0] [0]
ですが、1要素タプルのボックス化解除のugさを避けています。
NumPyには、これを達成するためにおそらくまとめることができる多くの操作があります。これは、アイテムに等しい要素のインデックスを返します:
numpy.nonzero(array - item)
リストの最初の要素を取得して、単一の要素を取得できます。
1次元の並べ替え配列の場合、 numpy.searchsorted は、NumPy整数(位置)を返します。たとえば、
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
配列が既にソートされていることを確認してください
また、返されたインデックスiに実際に検索された要素が含まれているかどうかを確認します。searchsortedの主な目的は、順序を維持するために要素を挿入するインデックスを見つけることです。
if arr[i] == 3:
print("present")
else:
print("not present")
np.where()から最初の要素を選択する代わりに、次のような列挙型とジェネレーター式を使用することもできます。
>>> import numpy as np
>>> x = np.arange(100) # x = array([0, 1, 2, 3, ... 99])
>>> next(i for i, x_i in enumerate(x) if x_i == 2)
2
2次元配列の場合:
>>> x = np.arange(100).reshape(10,10) # x = array([[0, 1, 2,... 9], [10,..19],])
>>> next((i,j) for i, x_i in enumerate(x)
... for j, x_ij in enumerate(x_i) if x_ij == 2)
(0, 2)
このアプローチの利点は、最初の一致が見つかった後に配列の要素のチェックを停止するのに対し、np.whereはすべての要素の一致をチェックすることです。配列の早い段階で一致する場合、ジェネレーター式は高速になります。
numpy_indexed パッケージ(免責事項、私はその著者)には、list.indexのベクトル化された同等物が含まれています。 numpy.ndarray;つまり:
sequence_of_arrays = [[0, 1], [1, 2], [-5, 0]]
arrays_to_query = [[-5, 0], [1, 0]]
import numpy_indexed as npi
idx = npi.indices(sequence_of_arrays, arrays_to_query, missing=-1)
print(idx) # [2, -1]
このソリューションは、ベクトル化されたパフォーマンスを持ち、ndarraysに一般化し、欠損値を処理するさまざまな方法があります。
注:これはPython 2.7バージョン用です
ラムダ関数を使用して問題を処理できます。 NumPy配列とリストの両方で機能します。
your_list = [11, 22, 23, 44, 55]
result = filter(lambda x:your_list[x]>30, range(len(your_list)))
#result: [3, 4]
import numpy as np
your_numpy_array = np.array([11, 22, 23, 44, 55])
result = filter(lambda x:your_numpy_array [x]>30, range(len(your_list)))
#result: [3, 4]
そして使用できます
result[0]
フィルタリングされた要素の最初のインデックスを取得します。
Python 3.6の場合、使用
list(result)
の代わりに
result