web-dev-qa-db-ja.com

pandasのMultiIndexインデックス列の値をクエリする方法

コード例:

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行が含まれます。テーブルのセルは数値です。たとえば、A double、B、C整数です。テーブルTのDataFrameを作成しましょう。DFと名付けましょう。 DFの列AとBのインデックスを設定してみましょう(重複なし、つまりインデックスとして別々の列AとBはなく、データとして分離)、つまりこの場合はAとBMultiIndex

質問:

  1. たとえば、ラベル間隔[120.0、540.0]で、インデックスA(またはB)をクエリするために、インデックスにクエリを書き込む方法は?ラベル120.0および540.0が存在します。クエリへの応答としてインデックスのリストのみに興味があることを明確にする必要があります!
  2. 同じ方法ですが、ラベル120.0および540.0の場合は存在しませんが、値が120未満、120を超え540未満、または540を超えるラベルがありますか?
  3. Q1とQ2の答えが一意のインデックス値であった場合、インデックス範囲内のデータ行の数と同じですが、繰り返します。

インデックスではない列の場合の上記の質問に対する答えを知っていますが、インデックスの場合は、Webでの長い調査とpandas、成功しませんでした。私が今見ている唯一の方法(追加のプログラミングなし)は、インデックスに加えてデータ列としてAとBの複製を持つことです。

54

dfMultiIndex値でクエリするには、たとえば(A> 1.7)and(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

読みやすくするために、単純に 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 

Q1A範囲[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

そしてもちろん、あらゆる種類のインクルードに対して<, <=, >, >=をいじることができます。


同様に、Q2A範囲[2.0, 4.0])に対する回答:

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

Q3B範囲内[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 ABのクエリを非常に自然に結合できます!

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