パンダシリーズで要素のインデックスを検索する


154

これは非常に基本的な質問であることはわかっていますが、何らかの理由で回答が見つかりません。python pandasでシリーズの特定の要素のインデックスを取得するにはどうすればよいですか?(最初の発生で十分です)

つまり、次のようなものを希望します。

import pandas as pd
myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
print myseries.find(7) # should output 3

確かに、そのようなメソッドをループで定義することは可能です:

def find(s, el):
    for i in s.index:
        if s[i] == el: 
            return i
    return None

print find(myseries, 7)

しかし、もっと良い方法があるはずだと思います。ある?

回答:


199
>>> myseries[myseries == 7]
3    7
dtype: int64
>>> myseries[myseries == 7].index[0]
3

それを行うにはもっと良い方法があるべきだと私は認めますが、これは少なくともオブジェクトの反復とループを回避し、オブジェクトをCレベルに移動します。


12
ここでの問題は、検索対象の要素が実際にリストにあると想定していることです。それは残念なパンダです。組み込みの検索操作がないようです。
jxramos 2017

7
このソリューションは、シリーズに連続した整数インデックスがある場合にのみ機能します。シリーズインデックスが日時順の場合、これは機能しません。
Andrew Medlin

43

インデックスに変換すると、使用できます get_loc

In [1]: myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])

In [3]: Index(myseries).get_loc(7)
Out[3]: 3

In [4]: Index(myseries).get_loc(10)
KeyError: 10

重複処理

In [5]: Index([1,1,2,2,3,4]).get_loc(2)
Out[5]: slice(2, 4, None)

連続していない場合はブール配列を返します

In [6]: Index([1,1,2,1,3,2,4]).get_loc(2)
Out[6]: array([False, False,  True, False, False,  True, False], dtype=bool)

内部でハッシュテーブルを使用しているため、高速

In [7]: s = Series(randint(0,10,10000))

In [9]: %timeit s[s == 5]
1000 loops, best of 3: 203 µs per loop

In [12]: i = Index(s)

In [13]: %timeit i.get_loc(5)
1000 loops, best of 3: 226 µs per loop

Viktorが指摘するように、インデックスを作成するための1回限りの作成オーバーヘッドがあります(実際にインデックスで何かを実行したときに発生しますis_unique)。

In [2]: s = Series(randint(0,10,10000))

In [3]: %timeit Index(s)
100000 loops, best of 3: 9.6 µs per loop

In [4]: %timeit Index(s).is_unique
10000 loops, best of 3: 140 µs per loop

1
@Jeffあなたがより興味深いインデックスを持っている場合、それはそれほど簡単ではありません...しかし、私はあなたがそれを行うことができると思いますs.index[_]
Andy Hayden

11
In [92]: (myseries==7).argmax()
Out[92]: 3

これは、7が事前に存在することがわかっている場合に機能します。これは(myseries == 7).any()で確認できます。

複数の7の(またはなし)も考慮に入れる別のアプローチ(最初の回答に非常に類似)は、

In [122]: myseries = pd.Series([1,7,0,7,5], index=['a','b','c','d','e'])
In [123]: list(myseries[myseries==7].index)
Out[123]: ['b', 'd']

7が事前に要素であることを知っているという点は正しいです。ただしany、2回の反復が必要になるため、チェックの使用は理想的ではありません。ここで確認Falseできるすべての条件を明らかにするクールなポスト運用チェックがあります
jxramos 2017

1
この条件に一致する要素がない場合argmaxでも、エラーが発生する代わりに0を返します。
cs95

8

ここでのすべての答えに感銘を受けました。これは新しい答えではなく、これらすべての方法のタイミングを要約する試みです。25要素のシリーズの場合を検討し、インデックスに任意の値を含めることができ、シリーズの終わりに近い検索値に対応するインデックス値が必要な一般的なケースを想定しました。

Pandasバージョン0.25.3を使用したPython 3.7の2013 MacBook Proの速度テストを以下に示します。

In [1]: import pandas as pd                                                

In [2]: import numpy as np                                                 

In [3]: data = [406400, 203200, 101600,  76100,  50800,  25400,  19050,  12700, 
   ...:          9500,   6700,   4750,   3350,   2360,   1700,   1180,    850, 
   ...:           600,    425,    300,    212,    150,    106,     75,     53, 
   ...:            38]                                                                               

In [4]: myseries = pd.Series(data, index=range(1,26))                                                

In [5]: myseries[21]                                                                                 
Out[5]: 150

In [7]: %timeit myseries[myseries == 150].index[0]                                                   
416 µs ± 5.05 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [8]: %timeit myseries[myseries == 150].first_valid_index()                                        
585 µs ± 32.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [9]: %timeit myseries.where(myseries == 150).first_valid_index()                                  
652 µs ± 23.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [10]: %timeit myseries.index[np.where(myseries == 150)[0][0]]                                     
195 µs ± 1.18 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [11]: %timeit pd.Series(myseries.index, index=myseries)[150]                 
178 µs ± 9.35 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [12]: %timeit myseries.index[pd.Index(myseries).get_loc(150)]                                    
77.4 µs ± 1.41 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [13]: %timeit myseries.index[list(myseries).index(150)]
12.7 µs ± 42.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [14]: %timeit myseries.index[myseries.tolist().index(150)]                   
9.46 µs ± 19.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

@ジェフの答えは最速のようです-それは重複を処理しませんが。

訂正:申し訳ありません。リストインデックスメソッドを使用した@Alex Spangherのソリューションは、最速です。

更新:@EliadLの回答を追加しました。

お役に立てれば。

このような単純な操作には、このような複雑なソリューションが必要であり、その多くが非常に遅いことは驚くべきことです。一連の25の値を見つけるには、0.5ミリ秒以上かかる場合があります。


1
ありがとう。しかし、一度作成すればよいので、作成 に測定してmyindexはいけませんか?
EliadL

あなたはそれを主張することができますが、それはこのようなルックアップがいくつ必要とされるかに依存します。myindexルックアップを何度も行う場合にのみ、シリーズを作成する価値があります。このテストでは、これは一度だけ必要であり、合計実行時間は重要であると想定しました。
ビル

1
今夜、これが必要になっただけで、同じインデックスオブジェクトで複数のルックアップにわたって.get_lock()を使用するのが最も高速なようです。答えの改善は、両方のタイミングを提供することだと思います:インデックスの作成と、作成後のルックアップのみの別のタイミングを含みます。
リックは

はい、良い点です。@EliadLもそう言った。シリーズが静的であるアプリケーションの数によって異なります。系列の値が変更された場合は、再構築する必要がありますpd.Index(myseries)。他の方法に公平を期するために、前回の検索以降、元のシリーズが変更された可能性があると想定しました。
ビル・

5

これを行うもう1つの方法は、同様に不十分ですが、次のとおりです。

s = pd.Series([1,3,0,7,5],index=[0,1,2,3,4])

list(s).index(7)

戻り値:3

私が作業している現在のデータセットを使用した時間テスト(ランダムと見なしてください):

[64]:    %timeit pd.Index(article_reference_df.asset_id).get_loc('100000003003614')
10000 loops, best of 3: 60.1 µs per loop

In [66]: %timeit article_reference_df.asset_id[article_reference_df.asset_id == '100000003003614'].index[0]
1000 loops, best of 3: 255 µs per loop


In [65]: %timeit list(article_reference_df.asset_id).index('100000003003614')
100000 loops, best of 3: 14.5 µs per loop

4

numpyを使用すると、値が見つかったインデックスの配列を取得できます。

import numpy as np
import pandas as pd
myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
np.where(myseries == 7)

これは、7がmyseriesの値である、インデックスの配列を含む1つの要素のタプルを返します。

(array([3], dtype=int64),)

3

あなたはSeries.idxmax()を使うことができます

>>> import pandas as pd
>>> myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
>>> myseries.idxmax()
3
>>> 

5
これは、max要素が見つかったインデックスのみを返すindex of certain elementようで、質問のような特定の要素は返されません。
jxramos

1

まだ言及されていないもう1つの方法は、tolistメソッドです。

myseries.tolist().index(7)

値がシリーズに存在する場合、正しいインデックスを返す必要があります。


1
@Alex Spangherは、2014年9月17日に同様のことを提案しました。彼の答えを見てください。テスト結果に両方のバージョンを追加しました。
ビル

0

多くの場合、値は複数のインデックスで発生します。

>>> myseries = pd.Series([0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1])
>>> myseries.index[myseries == 1]
Int64Index([3, 4, 5, 6, 10, 11], dtype='int64')

0

これは私が見つけることができる最もネイティブでスケーラブルなアプローチです:

>>> myindex = pd.Series(myseries.index, index=myseries)

>>> myindex[7]
3

>>> myindex[[7, 5, 7]]
7    3
5    4
7    3
dtype: int64
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.