Temukan indeks elemen dalam Seri panda

154

Saya tahu ini adalah pertanyaan yang sangat mendasar tetapi untuk beberapa alasan saya tidak dapat menemukan jawaban. Bagaimana saya bisa mendapatkan indeks elemen tertentu dari Seri di python panda? (Kejadian pertama sudah cukup)

Yaitu, saya ingin sesuatu seperti:

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

Tentu saja, dimungkinkan untuk mendefinisikan metode seperti itu dengan sebuah loop:

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

print find(myseries, 7)

tapi saya berasumsi harus ada cara yang lebih baik. Disana?

sashkello
sumber

Jawaban:

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

Meskipun saya akui bahwa seharusnya ada cara yang lebih baik untuk melakukan itu, tetapi ini setidaknya menghindari iterasi dan perulangan melalui objek dan memindahkannya ke level C.

Viktor Kerkez
sumber
12
Masalahnya di sini adalah mengasumsikan elemen yang dicari sebenarnya ada dalam daftar. Ini adalah panda yang mengecewakan sepertinya tidak memiliki operasi pencarian bawaan.
jxramos
7
Solusi ini hanya berfungsi jika seri Anda memiliki indeks integer berurutan. Jika indeks seri Anda berdasarkan waktu, ini tidak berfungsi.
Andrew Medlin
43

Konversi ke Indeks, dapat Anda gunakan 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

Penanganan duplikat

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

Akan mengembalikan array boolean jika pengembalian tidak bersebelahan

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)

Menggunakan hashtable secara internal, sangat cepat

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

Seperti yang ditunjukkan Viktor, ada overhead penciptaan satu kali untuk membuat indeks (terjadi ketika Anda benar-benar MELAKUKAN sesuatu dengan indeks, misalnya 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
sumber
1
@ Jeff jika Anda memiliki indeks yang lebih menarik itu tidak begitu mudah ... tapi saya rasa Anda bisa melakukannyas.index[_]
Andy Hayden
11
In [92]: (myseries==7).argmax()
Out[92]: 3

Ini berfungsi jika Anda tahu 7 ada di muka. Anda dapat memeriksa ini dengan (myseries == 7) .any ()

Pendekatan lain (sangat mirip dengan jawaban pertama) yang juga mencakup beberapa 7 (atau tidak ada) adalah

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
sumber
Poin tentang mengetahui 7 adalah elemen di muka sudah tepat. Namun menggunakan anycek tidak ideal karena iterasi ganda diperlukan. Ada pemeriksaan op pos keren yang akan mengungkap semua Falsekondisi yang dapat Anda lihat di sini .
jxramos
1
Hati-hati, jika tidak ada elemen yang cocok dengan kondisi ini, argmaxmasih akan mengembalikan 0 (bukannya kesalahan keluar).
cs95
8

Saya terkesan dengan semua jawaban di sini. Ini bukan jawaban baru, hanya upaya untuk meringkas penentuan waktu semua metode ini. Saya mempertimbangkan kasus seri dengan 25 elemen dan mengasumsikan kasus umum di mana indeks dapat berisi nilai apa pun dan Anda menginginkan nilai indeks yang sesuai dengan nilai pencarian yang menjelang akhir seri.

Berikut adalah tes kecepatan pada MacBook Pro 2013 di Python 3.7 dengan Pandas versi 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)

@ Jeff menjawab sepertinya yang tercepat - meskipun tidak menangani duplikat.

Koreksi : Maaf, saya melewatkan satu, solusi @Alex Spangher menggunakan metode daftar indeks sejauh ini tercepat.

Pembaruan : Menambahkan jawaban @ EliadL.

Semoga ini membantu.

Luar biasa bahwa operasi yang begitu sederhana membutuhkan solusi berbelit-belit dan banyak yang sangat lambat. Lebih dari setengah milidetik dalam beberapa kasus menemukan nilai dalam serangkaian 25.

Tagihan
sumber
1
Terima kasih. Tapi bukankah seharusnya Anda mengukur setelah myindex dibuat, karena itu hanya perlu dibuat sekali?
EliadL
Anda bisa membantahnya tetapi itu tergantung pada berapa banyak pencarian seperti ini diperlukan. Anda hanya perlu membuat myindexseri jika ingin melakukan pencarian berulang kali. Untuk tes ini saya berasumsi itu hanya diperlukan sekali dan waktu eksekusi total adalah penting.
Bill
1
Hanya berlari ke kebutuhan ini malam ini, dan menggunakan .get_lock () pada objek Indeks yang sama di beberapa pencarian sepertinya itu harus menjadi yang tercepat. Saya pikir peningkatan jawaban adalah dengan menyediakan timing untuk keduanya: termasuk pembuatan Indeks, dan waktu pencarian hanya setelah itu telah dibuat.
Rick mendukung Monica
Ya, poin bagus. @EliadL juga mengatakan itu. Tergantung pada berapa banyak aplikasi seri ini statis. Jika ada nilai dalam seri yang berubah, Anda perlu membangun kembali pd.Index(myseries). Agar adil dengan metode lain saya berasumsi seri asli mungkin telah berubah sejak pencarian terakhir.
Bill
5

Cara lain untuk melakukan ini, meskipun sama-sama tidak memuaskan adalah:

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

list(s).index(7)

pengembalian: 3

Pada tes waktu menggunakan dataset saat ini saya bekerja dengan (menganggapnya acak):

[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
sumber
4

Jika Anda menggunakan numpy, Anda bisa mendapatkan array dari indecies yang nilainya ditemukan:

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)

Ini mengembalikan satu elemen tuple yang berisi array dari indecies di mana 7 adalah nilai di myseries:

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

Anda dapat menggunakan Series.idxmax ()

>>> import pandas as pd
>>> myseries = pd.Series([1,4,0,7,5], index=[0,1,2,3,4])
>>> myseries.idxmax()
3
>>> 
Raki Gade
sumber
5
Tampaknya ini hanya mengembalikan indeks tempat elemen maks ditemukan, bukan spesifik index of certain elementseperti pertanyaan yang diajukan.
jxramos
1

Cara lain untuk melakukannya yang belum disebutkan adalah metode tolist:

myseries.tolist().index(7)

harus mengembalikan indeks yang benar, dengan asumsi nilai ada di Seri.

rmutalik
sumber
1
@Alex Spangher menyarankan hal serupa pada 17 Sep '14. Lihat jawabannya. Saya sekarang telah menambahkan kedua versi ke hasil tes.
Bill
0

Seringkali nilai Anda muncul di beberapa indeks:

>>> 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
sumber
0

Ini adalah pendekatan paling asli dan terukur yang bisa saya temukan:

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

>>> myindex[7]
3

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