Panda Serisinde öğenin dizinini bulun


154

Bunun çok temel bir soru olduğunu biliyorum ama nedense bir cevap bulamıyorum. Python pandalarında bir Serinin belirli elemanlarının dizinini nasıl alabilirim? (ilk olay yeterli olur)

Yani, şöyle bir şey istiyorum:

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

Elbette, böyle bir yöntemi bir döngü ile tanımlamak mümkündür:

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

print find(myseries, 7)

ama daha iyi bir yol olması gerektiğini düşünüyorum. Var mı?

Yanıtlar:


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

Bunu yapmanın daha iyi bir yolu olduğunu itiraf etsem de, bu en azından nesnenin yinelenmesini ve döngüsünü önler ve onu C seviyesine taşır.


12
Buradaki sorun, aranan öğenin aslında listede olduğunu varsayar. Bu bir serseri pandaların yerleşik bir bulma işlemi yok gibi görünüyor.
jxramos

7
Bu çözüm yalnızca dizinizde sıralı bir tamsayı dizini varsa çalışır. Seri dizininiz tarih saatindeyse, bu çalışmaz.
Andrew Medlin

43

Bir Endekse Dönüştürme'yi kullanabilirsiniz. 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

Çift işlem

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

Bitişik olmayan döndürürse bir boolean dizisi döndürür

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)

Bir hashtable'ı dahili olarak kullanır, çok hızlı

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 işaret ettiği gibi, bir kerelik oluşturma dizin oluşturmanın havai var (, aslında indeksi ile bir şeyler DO zaman onun katlanılan örn 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 daha ilginç bir indeksiniz varsa o kadar kolay değil ... ama sanırım bunu yapabilirsinizs.index[_]
Andy Hayden

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

7'nin önceden orada olduğunu biliyorsanız bu işe yarar. Bunu (myseries == 7) .any () ile kontrol edebilirsiniz.

Birden fazla 7'yi (veya hiçbirini) hesaba katan başka bir yaklaşım (ilk cevaba çok benzer)

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'yi tanıma ile ilgili nokta, önceden doğru olan bir unsurdur. Ancak any, çift yinelemeye ihtiyaç duyulduğu için bir kontrol kullanmak ideal değildir. Burada Falsegörebileceğiniz tüm koşulları açığa çıkaracak havalı bir post op kontrolü var .
jxramos

1
Dikkat edin, bu koşulla eşleşen hiçbir öğe argmaxhala 0 döndürmez (hata yapmak yerine).
cs95

8

Buradaki tüm cevaplardan çok etkilendim. Bu yeni bir cevap değil, tüm bu yöntemlerin zamanlamalarını özetleme çabasıdır. 25 elemanlı bir seriyi ele aldım ve indeksin herhangi bir değer içerebileceği genel bir durum varsaydım ve dizin değerinin serinin sonuna doğru olan arama değerine karşılık gelmesini istiyorum.

İşte Pandas sürüm 0.25.3 ile Python 3.7'de 2013 MacBook Pro'da hız testleri.

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'in cevabı en hızlı gibi görünüyor - yinelemeleri ele almasa da.

Düzeltme : Üzgünüm, bir özledim, @Alex Spangher listesi dizin yöntemi kullanarak çözüm çok hızlı.

Güncelleme : @ EliadL'nin cevabı eklendi.

Bu yardımcı olur umarım.

Böyle basit bir işlemin bu kadar kıvrımlı çözümler gerektirmesi şaşırtıcıdır ve birçoğu çok yavaştır. Bazı durumlarda yarım milisaniyeden fazla bir süre 25 serisinde bir değer bulmak için.


1
Teşekkürler. Ancak oluşturulduktan sonra myindex ölçmemelisiniz, çünkü sadece bir kez yaratılması gerekir mi?
EliadL

Bunu iddia edebilirsiniz, ancak bunun kaç tane arama gerektiğine bağlı. Diziyi sadece myindexarama işlemini birçok kez yapacaksanız yaratmaya değer . Bu test için sadece bir kez gerekli olduğunu ve toplam yürütme süresinin önemli olduğunu varsaydım.
Bill

1
Sadece bu gece buna ihtiyaç duyduk ve birden çok aramada aynı Index nesnesinde .get_lock () kullanmak, en hızlı olması gerektiği gibi görünüyor. Bence cevapta bir gelişme her ikisi için de zamanlama sağlamak olacaktır: Dizin oluşturma ve sadece oluşturulduktan sonra arama başka bir zamanlama.
Rick, Monica'yı

Evet, iyi bir noktaya değindiniz. @EliadL de söyledi. Serinin kaç uygulamada statik olduğuna bağlıdır. Serideki herhangi bir değer değişirse, yeniden oluşturmanız gerekir pd.Index(myseries). Diğer yöntemlere karşı adil olmak gerekirse, orijinal dizinin son aramadan bu yana değişmiş olabileceğini varsaydım.
Bill

5

Eşit derecede tatmin edici olmamasına rağmen bunu yapmanın başka bir yolu:

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

list(s).index(7)

döner: 3

Üzerinde çalıştığım geçerli bir veri kümesini kullanan zaman testlerinde (rastgele düşünün):

[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 kullanırsanız, değerinizin bulunduğu bir dizi dizin alabilirsiniz:

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)

Bu, dizinlerin bir dizisini içeren tek bir öğe demetini döndürür; burada 7, myseries'deki değerdir:

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

3

Series.idxmax () kullanabilirsiniz

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

5
Bu, yalnızca max öğesinin bulunduğu dizini döndürüyor index of certain elementgibi görünüyor, sorulan soru gibi spesifik değil .
jxramos

1

Henüz belirtilmemiş olan başka bir yol tolist yöntemidir:

myseries.tolist().index(7)

Seride değerin var olduğu varsayılarak doğru dizini döndürmelidir.


1
@Alex Spangher, 17 Eylül 14'te benzer bir şey önerdi. Cevabına bakın. Şimdi her iki sürümü de test sonuçlarına ekledim.
Bill

0

Genellikle değeriniz birden çok endekste gerçekleşir:

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

Bulabildiğim en doğal ve ölçeklenebilir yaklaşım:

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

>>> myindex[7]
3

>>> myindex[[7, 5, 7]]
7    3
5    4
7    3
dtype: int64
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.