首页 文章

如何查询pandas中的MultiIndex索引列值

提问于
浏览
35

代码示例:

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值:
Q3 :在重复范围[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和B的MultiIndex .

问题:

  • 如何在索引上编写查询,例如,查询索引A(或B),比如标签区间[120.0,540.0]?存在标签120.0和540.0 . 我必须澄清,我只对索引列表感兴趣,作为对查询的响应!

  • 如何相同,但如果标签120.0和540.0不存在,但有标签值低于120,高于120且低于540,或高于540?

  • 如果Q1和Q2的答案是唯一索引值,现在相同,但重复,作为索引范围内的数据行数 .

我知道上述问题的答案是在不是索引的列的情况下,但在索引的情况下,经过长期的网络研究和对熊猫功能的实验,我没有成功 . 我现在看到的唯一方法(没有额外的编程)除了索引之外还有A和B的副本作为数据列 .

3 回答

  • 49

    For better readability ,我们可以简单地使用the query() Method,以避免冗长的 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
    
  • 23

    使用类似索引的'float',您总是希望将其用作列而不是直接索引操作 . 无论 endpoints 是否存在,这些都将起作用 .

    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

    要通过MultiIndex值查询df,例如where(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
    

相关问题