配列内の何かの最初のインデックスを返すNumPy関数はありますか?


回答:


523

はい、ここにNumPy配列array、および値が指定された場合のitem検索結果を示します。

itemindex = numpy.where(array==item)

結果は、最初にすべての行インデックス、次にすべての列インデックスを持つタプルです。

たとえば、配列が2次元で、2つの場所にアイテムが含まれている場合

array[itemindex[0][0]][itemindex[1][0]]

あなたのアイテムと等しいでしょう

array[itemindex[0][1]][itemindex[1][1]]

numpy.where


1
最初の列にアイテムが存在する最初の行を探している場合、これは機能します(存在しない場合はインデックスエラーがスローされます)rows, columns = np.where(array==item); first_idx = sorted([r for r, c in zip(rows, columns) if c == 0])[0]
BrT

29
最初の値を見つけた後で検索を停止したい場合はどうでしょうか?where()がfind()に匹敵するとは思いません
Michael Clerx '20

2
ああ!あなたはパフォーマンスに興味があれば、この質問への答えをチェックアウト:stackoverflow.com/questions/7632963/...
マイケルClerx

11
np.argwhereここで少し役立つでしょう:itemindex = np.argwhere(array==item)[0]; array[tuple(itemindex)]
Eric

3
この答えは、配列が2Dであると想定していることに注意してください。where任意の配列で動作し、3次元アレイ等に使用されたときの長さ3のタプルを返すであろう
P. Camilleri

70

値が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]),)

3sの両方のサブシーケンスと8sの両方のサブシーケンスの先頭を見つけることに注意してください。

[ 1、1、1、2、2、3838、8]

したがって、各値の最初の出現を見つけることとは少し異なります。プログラムでは、のソートされたバージョンを使用tして、必要なものを取得できる場合があります。

>>> st = sorted(t)
>>> nonzero(r_[1, diff(st)[:-1]])
(array([0, 3, 5, 7]),)

4
何について説明していただけますr_か?
Geoff

1
@Geoff、r_連結します。または、より正確には、スライスオブジェクトを各軸に沿った連結に変換します。hstack代わりに使用できました。混乱が少ないかもしれません。の詳細については、ドキュメントを参照してくださいr_。もありc_ます。
Vebjorn Ljosa

+1、いいね!(NP.where対)あなたのソリューションは、それは我々が必要とする1次元配列内の指定された値の最初のオカレンスだけだ場合にはずっと簡単(そしておそらくより速い)である
ダグ

3
後者のケース(すべての値の最初のインデックスを見つける)は、vals, locs = np.unique(t, return_index=True)
askewchan

@askewchanあなたのバージョンは機能的には同等ですが、はるかに遅い
Jivan

50

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を出力します。


ライブラリが最初に作成されてから変更されている可能性があります。しかし、これは私にとってうまくいった最初の解決策でした。
amracel

1
私は、リストの内包表記を使用して、リスト内の複数の値を見つけるために、これをうまく利用して作った:[find_list.index(index_list[i]) for i in range(len(index_list))]
マット・ウェンハム

1
@MattWenham十分に大きい場合はfind_list、NumPy配列object(または適切な具体的なもの)のNumPy配列に変換して、を実行しますfind_arr[index_list]
Narfanar

まったく話題外ですが、「空中で」というフレーズを目にしたのはこれが初めてです。その場所で私が最もよく目にしたのは、おそらく「その場で」です。
flow2k

18

非常に高性能で便利な np.ndenumerate最初のインデックスを見つけるために基づく代替:

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.wherenp.nonzero


ただしnp.argwhereも対処でき優雅に多次元配列で(手動タプルにキャストする必要があるだろうし、それが短絡していないのです)が、一致が見つからない場合、それは失敗します。

>>> tuple(np.argwhere(arr1 == 2)[0])
(2, 2, 2)
>>> tuple(np.argwhere(arr2 == 2)[0])
(5,)

2
@njit短縮であるjit(nopython=True)機能は完全にオンザフライPythonインタプリタコールが完全に除去されるように、最初の実行時にコンパイルされますすなわち。
bartolo-otrit 2018年

14

これを別のものへのインデックスとして使用する場合、配列がブロードキャスト可能な場合はブールインデックスを使用できます。明示的なインデックスは必要ありません。これを行う最も簡単な方法は、真理値に基づいてインデックスを作成することです。

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であると想定)、およびインデックスの配列の最初のアイテム用です。


10

l.index(x)iがリスト内で最初に出現するxのインデックスになるような最小のiを返します。

index()最初の一致を見つけた後に停止するようにPython の関数が実装されていると安全に想定でき、これにより最適な平均パフォーマンスが得られます。

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の中に他の機能があります(argmaxwhere、およびnonzero)配列の要素を検索するために使用されるが、彼らはすべてを探して全体の配列を通過するという欠点持つことができるすべてのための最初の要素を発見するために最適化されていない、出現を。また、配列wherenonzero返すため、最初の要素を選択してインデックスを取得する必要があることにも注意してください。

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),)

時間比較

大規模な配列の場合、イテレーターを使用したソリューションの方が、検索された項目が配列の先頭にある場合%timeitIPythonシェルで使用)の方が速いことを確認するだけです。

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の問題です。

参照:Numpy:値の最初のインデックスをすばやく検索


1
読者があなたのアプローチを使用したときに最悪の場合に何が起こるかを知るために、最悪のケース(最後の要素)のタイミングも含める必要があると思います。
MSeifert 2017年

@MSeifert最悪の場合のイテレータソリューションの適切なタイミングを取得できません。問題の原因がわかるまで、この回答を削除します
user2314737

1
動作しません%timeit next((idx for idx, val in np.ndenumerate(a) if val==99999))か?なぜそれが1000倍遅いのか疑問に思っている場合-numpy配列に対するPythonループが悪名高いほど遅いためです。
MSeifert

@MSeifertいいえ私は知りませんでしたが、私はまた、という事実によって困惑していますargmaxし、where(配列の最後に要素を検索)この場合にははるかに高速です
user2314737

要素が最初にあるかのように高速でなければなりません。それらは常に配列全体を処理するため、常に同じ時間がかかります(少なくとも必要です)。
MSeifert

9

1次元のソートされた配列の場合、NumPy整数(位置)を返すnumpy.searchsortedを使用する方がはるかに簡単で効率的なO(log(n))です。例えば、

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")

2
searchsortedは、検索前に配列をソートしないため、nlog(n)ではありません。引数の配列はすでにソートされていると想定しています。numpy.searchsorted(上記のリンク)のドキュメントを確認してください
Alok Nayak

6

任意の基準でインデックスを作成するには、次のようにすることができます。

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]

5

一次元アレイの場合、私がお勧めnp.flatnonzero(array == value)[0]の両方に相当する、np.nonzero(array == value)[0][0]そしてnp.where(array == value)[0][0]しかし1要素のタプルをボックス化解除の醜さを回避します。


4

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はすべての要素の一致をチェックすることです。配列の初期に一致がある場合、ジェネレータ式はより高速になります。


配列がまったく一致しない場合でも、このメソッドを使用すると、フォールバック値を簡単に指定できます。最初の例がNoneフォールバックとして戻る場合は、になりnext((i for i, x_i in enumerate(x) if x_i == 2), None)ます。
Erlend Magnus Viggen

4

NumPyには、おそらくこれを実現するために組み合わせることができる多くの操作があります。これはitemに等しい要素のインデックスを返します:

numpy.nonzero(array - item)

次に、リストの最初の要素を取得して、単一の要素を取得します。


5
それはitemに等しくないすべての要素のインデックスを与えませんか?
Autoplectic 2009年

3

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に一般化し、欠損値を処理するさまざまな方法を備えています。


-1

注:これは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

これにより、<filter object at 0x0000027535294D30>Python 3が実行されます(Python 3.6.3でテスト済み)。たぶんPython 3のアップデートですか?
Peter Mortensen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.