programing

Pandas에서 MultiIndex 인덱스 열 값을 쿼리하는 방법

randomtip 2021. 1. 14. 08:12
반응형

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 값 :
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를 복제하는 것입니다.


질의에 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

가독성을 위해 , 우리는 간단하게 사용할 수 있습니다 방법을 긴 피하기 위해, / 에 이리저리합니다.query()df.index.get_level_values()reset_indexset_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 

Answer for Q3 (B in range [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

And moreover, you can COMBINE the query for col A and B very naturally!

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

With a 'float' like index you always want to use it as a column rather than a direct indexing action. These will all work whether the endpoints exist or not.

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

If you want the indices back, just set them. This is a cheap operation.

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

If you REALLY want the actual index values

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

ReferenceURL : https://stackoverflow.com/questions/17921010/how-to-query-multiindex-index-columns-values-in-pandas

반응형