211 votes

Trouver l'index d'un élément dans la série pandas.

Je sais que c'est une question très basique mais pour une raison quelconque, je ne trouve pas de réponse. Comment puis-je obtenir l'index d'un certain élément d'une série en python pandas ? (la première occurrence suffirait)

C'est-à-dire que j'aimerais quelque chose comme :

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

Il est certainement possible de définir une telle méthode avec une boucle :

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

print find(myseries, 7)

mais je suppose qu'il devrait y avoir un meilleur moyen. Y en a-t-il une ?

258voto

Viktor Kerkez Points 11222
>>> myseries[myseries == 7]
3    7
dtype: int64
>>> myseries[myseries == 7].index[0]
3

J'admets qu'il devrait y avoir un meilleur moyen de le faire, mais cela évite au moins d'itérer et de boucler à travers l'objet et le déplace au niveau C.

55voto

Jeff Points 27612

En convertissant en un index, vous pouvez utiliser 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

Traitement des doublons

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

Retournera un tableau booléen si les retours ne sont pas contigus.

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)

Utilise une table de hachage en interne, donc rapide.

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

Comme Viktor l'a souligné, la création d'un index entraîne des frais de création uniques (ces frais sont encourus lorsque l'on FAIT quelque chose avec l'index, par exemple, la fonction 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

22voto

Bill Points 23

Je suis impressionné par toutes les réponses ici. Ce n'est pas une nouvelle réponse, juste une tentative de résumer les délais de toutes ces méthodes. J'ai considéré le cas d'une série de 25 éléments et supposé le cas général où l'index peut contenir n'importe quelles valeurs et où vous voulez la valeur d'index correspondant à la valeur de recherche qui se trouve vers la fin de la série.

Voici les tests de vitesse sur un Mac Mini 2012 dans Python 3.9.10 avec Pandas version 1.4.0.

In [1]: import pandas as pd

In [2]: import numpy as np

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

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

In [5]: assert(myseries[21] == 150)

In [6]: %timeit myseries[myseries == 150].index[0]
179 µs ± 891 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

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

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

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

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

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

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

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

In [14]: %timeit dict(zip(myseries.values, myseries.index))[150]
9.89 µs ± 79.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [15]: %timeit {v: k for k, v in myseries.items()}[150]
9.99 µs ± 67 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

La réponse de @Jeff semble être la plus rapide - bien qu'elle ne gère pas les doublons.

Correction : Désolé, j'en ai oublié un, la solution de @Alex Spangher utilisant la méthode de l'indice de liste est de loin la plus rapide.

Mise à jour : Ajouté la réponse de @EliadL.

J'espère que cela vous aidera.

Il est étonnant qu'une opération aussi simple nécessite des solutions aussi alambiquées et que beaucoup soient aussi lentes. Plus d'une demi-milliseconde dans certains cas pour trouver une valeur dans une série de 25.

2022-02-18 Mise à jour

Mise à jour de tous les timings avec la dernière version de Pandas et Python 3.9. Même sur un ordinateur plus ancien, tous les temps ont considérablement diminué (10 à 70%) par rapport aux tests précédents (version 0.25.3).

Plus : Ajout de deux méthodes supplémentaires utilisant des dictionnaires.

15voto

Alon Points 701
In [92]: (myseries==7).argmax()
Out[92]: 3

Cela fonctionne si vous savez à l'avance que 7 est là. Vous pouvez le vérifier avec (myseries==7).any()

Une autre approche (très similaire à la première réponse) qui prend également en compte les 7 multiples (ou aucun) est la suivante

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']

9voto

Alex Spangher Points 132

Une autre façon de procéder, tout aussi insatisfaisante, est la suivante :

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

list(s).index(7)

retours : 3

Tests en temps réel à l'aide d'un ensemble de données sur lequel je travaille actuellement (considérez-le comme aléatoire) :

[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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X