ค้นหาดัชนีขององค์ประกอบในซีรีย์นุ่น


154

ฉันรู้ว่านี่เป็นคำถามพื้นฐาน แต่ด้วยเหตุผลบางอย่างฉันไม่สามารถหาคำตอบได้ ฉันจะรับดัชนีขององค์ประกอบบางอย่างของซีรี่ส์ใน python 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

แม้ว่าฉันยอมรับว่าควรมีวิธีที่ดีกว่าในการทำเช่นนี้ แต่อย่างน้อยก็หลีกเลี่ยงการวนซ้ำและวนลูปผ่านวัตถุและย้ายไปยังระดับ C


12
ปัญหาที่นี่คือมันถือว่าองค์ประกอบที่กำลังค้นหาอยู่ในรายการจริง มันเป็นหมีแพนด้าที่น่ากลัว แต่ดูเหมือนว่าจะไม่มีตัวดำเนินการค้นหา
jxramos

7
วิธีนี้ใช้ได้เฉพาะเมื่อซีรี่ส์ของคุณมีดัชนีจำนวนเต็มตามลำดับ หากดัชนีชุดของคุณตามวันที่และเวลามันไม่ทำงาน
Andrew Medlin

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)

ใช้ hashtable ภายในอย่างรวดเร็ว

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 ชี้ให้เห็นว่ามีค่าใช้จ่ายในการสร้างเพียงครั้งเดียวในการสร้างดัชนี (เกิดขึ้นเมื่อคุณทำบางสิ่งบางอย่างกับดัชนีเช่น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
@ เจฟฟ์ถ้าคุณมีดัชนีที่น่าสนใจมากกว่านี้มันไม่ง่ายนัก ... แต่ฉันเดาว่าคุณทำได้s.index[_]
Andy Hayden

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ตรวจสอบไม่เหมาะเนื่องจากจำเป็นต้องใช้การวนซ้ำสองครั้ง มีการตรวจสอบการโพสต์ op เย็นที่จะเปิดตัวทั้งหมดเป็น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)

@ คำตอบของ Jeff ดูเหมือนจะเร็วที่สุด - แม้ว่ามันจะไม่จัดการกับข้อมูลซ้ำก็ตาม

การแก้ไข : ขออภัยฉันพลาดวิธีแก้ปัญหาของ @Alex Spangher โดยใช้วิธีรายการดัชนีนั้นเร็วที่สุด

อัปเดต : เพิ่มคำตอบของ @ EliadL

หวังว่านี่จะช่วยได้

น่าอัศจรรย์ที่การดำเนินการอย่างง่ายเช่นนี้ต้องการโซลูชันที่ซับซ้อนและหลายอย่างช้ามาก มากกว่าครึ่งมิลลิวินาทีในบางกรณีเพื่อค้นหาค่าในชุดของ 25


1
ขอบคุณ แต่คุณไม่ควรทำการวัดหลังจาก myindexถูกสร้างขึ้นเพราะมันจะต้องสร้างเพียงครั้งเดียว
EliadL

คุณอาจโต้แย้งว่า แต่ขึ้นอยู่กับจำนวนการค้นหาเช่นนี้ที่จำเป็น มันก็คุ้มค่าที่จะสร้างmyindexซีรีส์ถ้าคุณจะค้นหาหลายต่อหลายครั้ง สำหรับการทดสอบนี้ฉันคิดว่ามันจำเป็นเพียงครั้งเดียวเท่านั้นและเวลาดำเนินการทั้งหมดนั้นมีความสำคัญ
Bill

1
เพิ่งพบความต้องการในคืนนี้และการใช้. get_lock () บนวัตถุดัชนีเดียวกันในการค้นหาหลายครั้งดูเหมือนว่ามันควรเร็วที่สุด ฉันคิดว่าการปรับปรุงคำตอบคือให้การกำหนดเวลาสำหรับทั้งสอง: รวมถึงการสร้างดัชนีและเวลาอื่นของการค้นหาเท่านั้นหลังจากที่ถูกสร้างขึ้นแล้ว
Rick สนับสนุนโมนิก้า

ใช่จุดดี @EliadL ยังพูดอีกว่า ขึ้นอยู่กับจำนวนแอพพลิเคชั่นที่เป็นแบบคงที่ ถ้าค่าใด ๆ pd.Index(myseries)ในการเปลี่ยนแปลงชุดคุณจะต้องสร้าง เพื่อความยุติธรรมกับวิธีการอื่น ๆ ฉันคิดว่าซีรี่ส์ดั้งเดิมอาจมีการเปลี่ยนแปลงตั้งแต่การค้นหาครั้งล่าสุด
Bill

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 คุณสามารถรับอาร์เรย์ของ indecies ที่พบค่าของคุณ:

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)

สิ่งนี้จะส่งคืน tuple องค์ประกอบหนึ่งที่มีอาร์เรย์ของ indecies โดยที่ 7 คือค่าใน myseries:

(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

อีกวิธีในการทำที่ยังไม่ได้กล่าวถึงเป็นวิธี tolist:

myseries.tolist().index(7)

ควรส่งคืนดัชนีที่ถูกต้องโดยสมมติว่ามีค่าอยู่ในซีรี่ส์


1
@Alex Spangher แนะนำสิ่งที่คล้ายกันในวันที่ 17 กันยายน '14 ดูคำตอบของเขา ฉันได้เพิ่มทั้งสองเวอร์ชันลงในผลการทดสอบแล้ว
Bill

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.