77

代码示例:

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

问题:

  1. 如何在索引上编写查询,例如查询索引 A(或 B),比如在标签区间 [120.0, 540.0] 中?存在标签 120.0 和 540.0。我必须澄清一下,我只对作为查询响应的索引列表感兴趣!
  2. 如何相同,但如果标签 120.0 和 540.0 不存在,但有标签值低于 120、高于 120 且低于 540 或高于 540?
  3. 如果 Q1 和 Q2 的答案是唯一索引值,现在相同,但有重复,作为索引范围内的数据行数。

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

4

3 回答 3

81

通过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
于 2013-08-07T12:51:15.223 回答
46

为了更好的可读性,我们可以简单地使用Method 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

当然,人们可以玩弄<, <=, >, >=任何一种包容。


同样,回答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 

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查询!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
于 2016-11-26T10:44:15.120 回答
10

使用类似“浮点”的索引,您总是希望将其用作列而不是直接索引操作。无论端点是否存在,这些都将起作用。

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

第一季度

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

第二季度

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

第三季度

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)]
于 2013-07-29T12:08:22.183 回答