it-swarm.dev

كيفية الاستعلام عن قيم أعمدة فهرس MultiIndex في pandas

مثال على الكود:

In [171]: A = np.array([1.1, 1.1, 3.3, 3.3, 5.5, 6.6])

In [172]: B = np.array([111, 222, 222, 333, 333, 777])

In [173]: C = randint(10, 99, 6)

In [174]: df = pd.DataFrame(Zip(A, B, C), columns=['A', 'B', 'C'])

In [175]: df.set_index(['A', 'B'], inplace=True)

In [176]: df
Out[176]: 
          C
A   B      
1.1 111  20
    222  31
3.3 222  24
    333  65
5.5 333  22
6.6 777  74 

الآن ، أريد استرداد القيم A:
Q1: في النطاق [3.3 ، 6.6] - قيمة الإرجاع المتوقعة: [3.3 ، 5.5 ، 6.6] أو [3.3 ، 3.3 ، 5.5 ، 6.6] في حالة مشاركة شاملة ، و [ 3.3 ، 5.5] أو [3.3 ، 3.3 ، 5.5] إن لم يكن.
Q2: في النطاق [2.0 ، 4.0] - قيمة الإرجاع المتوقعة: [3.3] أو [3.3 ، 3.3]

نفس الشيء بالنسبة لأي بُعد آخر MultiIndex ، على سبيل المثال قيم B:
Q: في النطاق [111 ، 500] مع التكرار ، كعدد من صفوف البيانات في النطاق - قيمة الإرجاع المتوقعة: [111 ، 222 ، 222 ، 333 ، 333]

اكثر رسمية:

لنفترض أن T عبارة عن جدول يحتوي على أعمدة A و B و C. يحتوي الجدول على n صفوف. خلايا الجدول هي أرقام ، على سبيل المثال أعداد صحيحة مزدوجة وباء وجيم. لنقم بإنشاء DataFrame من الجدول T ، واسمحوا لنا DF. لنقم بتعيين فهارس A و B من DF (بدون ازدواجية ، أي عدم وجود أعمدة منفصلة A و B كـ فهارس ، وفصل كبيانات) ، أي A و B في هذه الحالة MultiIndex .

الأسئلة:

  1. كيفية كتابة استعلام على الفهرس ، على سبيل المثال ، للاستعلام عن الفهرس A (أو B) ، قل في الفاصل الزمني للتسميات [120.0 ، 540.0]؟ تسميات 120.0 و 540.0 موجودة. يجب أن أوضح أنني مهتم فقط بقائمة المؤشرات كرد على الاستعلام!
  2. كيف نفس الشيء ، ولكن في حالة وجود تسميات 120.0 و 540.0 غير موجودة ، ولكن هناك تسميات بقيمة أقل من 120 ، أعلى من 120 وأقل من 540 ، أو أعلى من 540؟
  3. في حالة كانت إجابة Q1 و Q2 هي قيم الفهرس الفريدة ، الآن هي نفسها ، ولكن مع التكرار ، كعدد من صفوف البيانات في نطاق الفهرس.

أعرف إجابات الأسئلة أعلاه في حالة الأعمدة التي ليست فهارس ، ولكن في حالة الفهارس ، بعد إجراء بحث طويل في الويب والتجريب باستخدام وظيفة الباندا ، أنا لم تنجح. الطريقة الوحيدة (بدون برمجة إضافية) التي أراها الآن هي الحصول على نسخة مكررة من A و B كأعمدة بيانات بالإضافة إلى الفهرس.

54
Vyacheslav Shkolyar

للاستعلام عن df بواسطة MultiIndex القيم ، على سبيل المثال ، (A> 1.7) و (B <666):

In [536]: result_df = df.loc[(df.index.get_level_values('A') > 1.7) & (df.index.get_level_values('B') < 666)]

In [537]: result_df
Out[537]: 
          C
A   B      
3.3 222  43
    333  59
5.5 333  56

وبالتالي ، على سبيل المثال للحصول على قيم الفهرس 'A' ، إذا كان لا يزال مطلوبًا:

In [538]: result_df.index.get_level_values('A')
Out[538]: Index([3.3, 3.3, 5.5], dtype=object)

المشكلة هي أنه في إطارات البيانات الكبيرة يكون أداء حسب الفهرس الاختيار أسوأ بنسبة 10٪ من اختيار الصفوف العادية المصنفة. وفي العمل المتكرر ، حلقات ، التأخير المتراكم. انظر المثال:

In [558]: df = store.select(STORE_EXTENT_BURSTS_DF_KEY)

In [559]: len(df)
Out[559]: 12857

In [560]: df.sort(inplace=True)

In [561]: df_without_index = df.reset_index()

In [562]: %timeit df.loc[(df.index.get_level_values('END_TIME') > 358200) & (df.index.get_level_values('START_TIME') < 361680)]
1000 loops, best of 3: 562 µs per loop

In [563]: %timeit df_without_index[(df_without_index.END_TIME > 358200) & (df_without_index.START_TIME < 361680)]
1000 loops, best of 3: 507 µs per loop
62
Vyacheslav Shkolyar

من أجل تحسين قابلية القراءة ، يمكننا ببساطة استخدام طريقة query() ، لتجنب الطول df.index.get_level_values() و reset_index/set_index ذهابا وإيابا.

هذا هو الهدف DataFrame:

In [12]: df                                                                    
Out[12]:                                                                       
          C                                                                    
A   B                                                                          
1.1 111  68                                                                    
    222  40                                                                    
3.3 222  20                                                                    
    333  11                                                                    
5.5 333  80                                                                    
6.6 777  51 

أجب عن Q1 (A في النطاق [3.3, 6.6]):

In [13]: df.query('3.3 <= A <= 6.6') # for closed interval                       
Out[13]:                                                                       
          C                                                                    
A   B                                                                          
3.3 222  20                                                                    
    333  11                                                                    
5.5 333  80                                                                    
6.6 777  51                                                                    

In [14]: df.query('3.3 < A < 6.6') # for open interval                         
Out[14]:                                                                       
          C                                                                    
A   B                                                                          
5.5 333  80

وبالطبع يمكن للمرء أن يلعب مع <, <=, >, >= لأي نوع من الإدماج.


وبالمثل ، أجب عن Q2 (A في النطاق [2.0, 4.0]):

In [15]: df.query('2.0 <= A <= 4.0')                                        
Out[15]:                                                                    
          C                                                                 
A   B                                                                       
3.3 222  20                                                                 
    333  11 

أجب عن Q3 (B في النطاق [111, 500]):

In [16]: df.query('111 <= B <= 500')                                        
Out[16]:                                                                    
          C                                                                 
A   B                                                                       
1.1 111  68                                                                 
    222  40                                                                 
3.3 222  20                                                                 
    333  11                                                                 
5.5 333  80

علاوة على ذلك ، يمكنك [~ # ~] الجمع بين [~ # ~] الاستعلام عن col A و B طبيعي جدا!

In [17]: df.query('0 < A < 4 and 150 < B < 400')                            
Out[17]:                                                                    
          C                                                                 
A   B                                                                       
1.1 222  40                                                                 
3.3 222  20                                                                 
    333  11
31
YaOzI

باستخدام فهرس "تعويم" ، ترغب دائمًا في استخدامه كعمود بدلاً من إجراء فهرسة مباشرة. ستعمل جميع هذه النقاط سواء كانت نقاط النهاية موجودة أم لا.

In [11]: df
Out[11]: 
          C
A   B      
1.1 111  81
    222  45
3.3 222  98
    333  13
5.5 333  89
6.6 777  98

In [12]: x = df.reset_index()

Q1

In [13]: x.loc[(x.A>=3.3)&(x.A<=6.6)]
Out[13]: 
     A    B   C
2  3.3  222  98
3  3.3  333  13
4  5.5  333  89
5  6.6  777  98

Q2

In [14]: x.loc[(x.A>=2.0)&(x.A<=4.0)]
Out[14]: 
     A    B   C
2  3.3  222  98
3  3.3  333  13

Q3

In [15]: x.loc[(x.B>=111.0)&(x.B<=500.0)]
Out[15]: 
     A    B   C
0  1.1  111  81
1  1.1  222  45
2  3.3  222  98
3  3.3  333  13
4  5.5  333  89

إذا كنت تريد عودة المؤشرات ، فقم فقط بتعيينها. هذه عملية رخيصة.

In [16]: x.loc[(x.B>=111.0)&(x.B<=500.0)].set_index(['A','B'])
Out[16]: 
          C
A   B      
1.1 111  81
    222  45
3.3 222  98
    333  13
5.5 333  89

إذا كنت تريد حقًا قيم الفهرس الفعلية

In [5]: x.loc[(x.B>=111.0)&(x.B<=500.0)].set_index(['A','B']).index
Out[5]: 
MultiIndex
[(1.1, 111), (1.1, 222), (3.3, 222), (3.3, 333), (5.5, 333)]
9
Jeff