Finden Sie den Index des Elements in der Pandas-Serie

154

Ich weiß, dass dies eine sehr grundlegende Frage ist, aber aus irgendeinem Grund kann ich keine Antwort finden. Wie kann ich den Index eines bestimmten Elements einer Serie in Python-Pandas abrufen? (erstes Auftreten würde ausreichen)

Dh ich hätte gerne etwas wie:

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

Natürlich ist es möglich, eine solche Methode mit einer Schleife zu definieren:

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

print find(myseries, 7)

aber ich gehe davon aus, dass es einen besseren Weg geben sollte. Gibt es?

Sashkello
quelle

Antworten:

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

Ich gebe zwar zu, dass es einen besseren Weg geben sollte, dies zu tun, aber dies vermeidet zumindest das Iterieren und Schleifen durch das Objekt und verschiebt es auf die C-Ebene.

Viktor Kerkez
quelle
12
Das Problem hierbei ist, dass davon ausgegangen wird, dass das gesuchte Element tatsächlich in der Liste enthalten ist. Es ist ein Mist, dass Pandas keine eingebaute Suchoperation haben.
Jxramos
7
Diese Lösung funktioniert nur, wenn Ihre Serie einen sequentiellen Ganzzahlindex hat. Wenn Ihr Serienindex nach Datum / Uhrzeit ist, funktioniert dies nicht.
Andrew Medlin
42

Konvertieren in einen Index können Sie verwenden 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

Doppelte Handhabung

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

Gibt ein boolesches Array zurück, wenn nicht zusammenhängend zurückgegeben wird

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)

Verwendet intern eine Hashtabelle, so schnell

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

Wie Viktor darauf hinweist, gibt es eine einmalige Schöpfung Kopf einen Index zu schaffen (das entstehen , wenn Sie tatsächlich etwas mit dem Index DO, zB 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
Jeff
quelle
1
@ Jeff, wenn Sie einen interessanteren Index haben, ist es nicht ganz so einfach ... aber ich denke, Sie können es einfach tuns.index[_]
Andy Hayden
11
In [92]: (myseries==7).argmax()
Out[92]: 3

Dies funktioniert, wenn Sie wissen, dass 7 im Voraus vorhanden ist. Sie können dies mit (myseries == 7) .any () überprüfen

Ein anderer Ansatz (der der ersten Antwort sehr ähnlich ist), der auch mehrere Siebenen (oder keine) berücksichtigt, ist

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']
Alon
quelle
Der Punkt, 7 zu kennen, ist ein Element im Voraus. Die Verwendung einer anyPrüfung ist jedoch nicht ideal, da eine doppelte Iteration erforderlich ist. Es gibt einen coolen Post-Op-Check, der alle FalseBedingungen enthüllt , die Sie hier sehen können .
Jxramos
1
Vorsicht, wenn kein Element dieser Bedingung entspricht, argmaxwird immer noch 0 zurückgegeben (anstatt einen Fehler zu machen).
CS95
7

Ich bin beeindruckt von all den Antworten hier. Dies ist keine neue Antwort, sondern nur ein Versuch, die Zeitabläufe all dieser Methoden zusammenzufassen. Ich habe den Fall einer Serie mit 25 Elementen betrachtet und den allgemeinen Fall angenommen, in dem der Index beliebige Werte enthalten könnte und Sie möchten, dass der Indexwert dem Suchwert entspricht, der sich gegen Ende der Serie befindet.

Hier sind die Geschwindigkeitstests auf einem 2013 MacBook Pro in Python 3.7 mit Pandas Version 0.25.3.

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)

@ Jeffs Antwort scheint die schnellste zu sein - obwohl sie keine Duplikate verarbeitet.

Korrektur : Entschuldigung, ich habe eine verpasst. Die Lösung von @Alex Spangher mit der Listenindexmethode ist bei weitem die schnellste.

Update : @ EliadLs Antwort hinzugefügt.

Hoffe das hilft.

Erstaunlich, dass solch eine einfache Operation solch komplizierte Lösungen erfordert und viele so langsam sind. In einigen Fällen über eine halbe Millisekunde, um einen Wert in einer Reihe von 25 zu finden.

Rechnung
quelle
1
Vielen Dank. Aber sollten Sie nicht messen, nachdem myindex erstellt wurde, da es nur einmal erstellt werden muss?
EliadL
Sie könnten das argumentieren, aber es hängt davon ab, wie viele Suchvorgänge wie diese erforderlich sind. Es lohnt sich nur, die myindexSerie zu erstellen , wenn Sie die Suche mehrmals durchführen. Für diesen Test habe ich angenommen, dass er nur einmal benötigt wurde und die gesamte Ausführungszeit wichtig war.
Bill
1
Ich bin heute Abend auf die Notwendigkeit gestoßen, und die Verwendung von .get_lock () für dasselbe Indexobjekt über mehrere Suchvorgänge hinweg scheint die schnellste zu sein. Ich denke, eine Verbesserung der Antwort wäre, die Timings für beide bereitzustellen: einschließlich der Indexerstellung und eines anderen Timings nur für die Suche nach der Erstellung.
Rick unterstützt Monica
Ja, guter Punkt. @EliadL hat das auch gesagt. Dies hängt davon ab, wie viele Anwendungen die Serie statisch ist. Wenn sich Werte in der Reihe ändern, müssen Sie neu erstellen pd.Index(myseries). Um den anderen Methoden gerecht zu werden, habe ich angenommen, dass sich die Originalserie seit der letzten Suche geändert hat.
Bill
5

Ein anderer Weg, dies zu tun, obwohl ebenso unbefriedigend, ist:

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

list(s).index(7)

Rückgabe: 3

Bei Zeittests mit einem aktuellen Datensatz, mit dem ich arbeite (als zufällig betrachten):

[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
Alex Spangher
quelle
4

Wenn Sie numpy verwenden, können Sie ein Array der Unabhängigkeiten abrufen, für die Ihr Wert gefunden wurde:

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)

Dies gibt ein Ein-Element-Tupel zurück, das ein Array der Unabhängigkeiten enthält, wobei 7 der Wert in myseries ist:

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

Sie können Series.idxmax () verwenden

>>> import pandas as pd
>>> myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
>>> myseries.idxmax()
3
>>> 
Raki Gade
quelle
5
Dies scheint nur den Index zurückzugeben, in dem sich das max-Element befindet, nicht einen bestimmten index of certain elementwie die gestellte Frage.
Jxramos
1

Eine andere Möglichkeit, die noch nicht erwähnt wurde, ist die Tolist-Methode:

myseries.tolist().index(7)

sollte den richtigen Index zurückgeben, vorausgesetzt, der Wert ist in der Serie vorhanden.

rmutalik
quelle
1
@ Alex Spangher schlug am 17. September 14 etwas Ähnliches vor. Siehe seine Antwort. Ich habe jetzt beide Versionen zu den Testergebnissen hinzugefügt.
Bill
0

Oft tritt Ihr Wert bei mehreren Indizes auf:

>>> 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')
Ulf Aslak
quelle
0

Dies ist der native und skalierbarste Ansatz, den ich finden konnte:

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

>>> myindex[7]
3

>>> myindex[[7, 5, 7]]
7    3
5    4
7    3
dtype: int64
EliadL
quelle