Знайдіть індекс елемента в серії pandas


154

Я знаю, що це дуже основне питання, але я чомусь не можу знайти відповідь. Як я можу отримати індекс певного елемента серії в пандах python? (перше виникнення буде достатньо)

Тобто, мені б хотілося чогось типу:

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

Хоча я визнаю, що повинен бути кращий спосіб зробити це, але це, принаймні, уникає ітерації та перекидання через об'єкт та переміщення його на рівень С.


12
Проблема тут полягає в тому, що він передбачає, що елемент, який шукають, є насправді в списку. Це, здається, не має вбудованих операцій пошуку.
— jxramos

7
Це рішення працює лише в тому випадку, якщо у вашої серії є послідовний цілий індекс. Якщо ваш індекс серії за датою, це не працює.
— Ендрю Медлін

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

Як зазначає Віктор, існує одноразове накладне створення індексу (воно виникає, коли ви дійсно щось робите з індексом, наприклад 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[_]
— Енді Хейден

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чека не є ідеальним, оскільки потрібна подвійна ітерація. Є класний пост перевірки, який відкриє всі Falseумови, які ви можете побачити тут .
— jxramos

1
Обережно, якщо жоден елемент не відповідає цій умові, argmaxусе одно поверне 0 (замість помилки).
— cs95

8

Я вражений усіма відповідями тут. Це не нова відповідь, а лише спроба узагальнити терміни всіх цих методів. Я розглянув випадок серії з 25 елементами і припустив загальний випадок, коли індекс міг містити будь-які значення, і ви хочете, щоб значення індексу відповідало значенню пошуку, яке знаходиться в кінці серії.

Ось тести швидкості на MacBook Pro 2013 року в Python 3.7 з версією Pandas 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)

@ Відповідь Джеффа здається найшвидшим - хоча він не обробляє дублікатів.

Виправлення : Вибачте, я пропустив рішення, рішення @Alex Spangher за допомогою методу списку індексу є найбільш швидким.

Оновлення : додано відповідь @ EliadL.

Сподіваюся, це допомагає.

Дивовижно, що така проста операція вимагає таких складних рішень, і багато хто так повільно. Більше половини мілісекунди в деяких випадках знайти значення в серії 25.


1
Дякую. Але ти не повинен вимірювати після myindex створення, оскільки потрібно лише створити один раз?
— EliadL

Ви можете заперечити це, але це залежить від того, скільки таких пошукових запитів потрібно. Створювати myindexсеріал варто лише в тому випадку, якщо ви збираєтеся шукати багато разів. Для цього тесту я припускав, що це потрібно лише один раз, і загальний час виконання був важливим.
— Білл

1
Щойно сьогодні ввечері виникло потреба в цьому, і використання .get_lock () на одному і тому ж об’єкті Index в декількох оглядах здається, що це повинно бути найшвидшим. Я думаю, що поліпшенням відповіді було б надання часу для обох: включаючи створення індексу та інший термін лише пошуку після його створення.
— Рік підтримує Моніку

Так, хороший момент. @EliadL також сказав це. Це залежить від того, скільки застосувань у серії є статичними. Якщо якісь значення в серії змінюються, вам потрібно відновити pd.Index(myseries). Щоб бути справедливим до інших методів, я припускав, що початкова серія могла змінитися з моменту останнього пошуку.
— Білл

5

Ще один спосіб зробити це, хоча не менш задовільно:

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 - значення в місеріях:

(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
Це, здається, повертає індекс лише там, де знайдений максимальний елемент, а не конкретний, index of certain elementяк запитання.
— jxramos

1

Ще один спосіб зробити це, про який ще не було сказано, - це метод списку:

myseries.tolist().index(7)

повинен повернути правильний індекс, вважаючи, що значення існує в Серії.


1
@Alex Spangher запропонував щось подібне 17 вересня 14 року. Дивіться його відповідь. Зараз я додав обидві версії до результатів тесту.
— Білл

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.