私は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であると仮定)のためのものであり、それからインデックスの配列の最初の項目のためのものです。
最初のインデックスを見つけるために np.ndenumerate
に基づいて非常に高性能で便利な numba 代替を追加するだけです。
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にキャストする必要があります および 短絡ではありません)。見つかった:
>>> Tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> Tuple(np.argwhere(arr2 == 2)[0])
(5,)
l.index(x)
は、最小の i を返します。 i は、リスト内でxが最初に現れるインデックスです。
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 Shellで%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 issue 。
任意の基準で索引を付けるには、次のようにします。
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]
の両方と同等ですが、1要素のTupleをアンボックス化する醜さを避けるnp.where(array == value)[0][0]
をお勧めします。
1次元の sorted 配列の場合、 numpy.searchsorted を使用すると、はるかに簡単で効率的なO(log(n))になり、NumPy整数(position)が返されます。 )例えば、
arr = np.array([1, 1, 1, 2, 3, 3, 4])
i = np.searchsorted(arr, 3)
配列がすでにソートされていることを確認してください。
Searchsortedの主な目的は、順序を維持するために要素を挿入する必要があるインデックスを見つけることであるため、返されたインデックスiが実際に検索された要素を含んでいるかどうかも確認します。
if arr[i] == 3:
print("present")
else:
print("not present")
これを達成するためにNumPyにはたぶんまとめることができるたくさんの操作があります。これはitemと等しい要素のインデックスを返します。
numpy.nonzero(array - item)
その後、リストの最初の要素を取得して単一の要素を取得できます。
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
二次元配列の場合は、次のようになります。
>>> 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 パッケージ(免責事項、私はその作者です)には、numpy.ndarrayのlist.indexのベクトル化された同等物が含まれています。あれは:
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]
このソリューションはパフォーマンスをベクトル化し、ndarrayに一般化し、欠損値を扱うさまざまな方法を持っています。