다중 인덱스 판다에서 선택


91

열 'A'와 'B'가있는 다중 인덱스 데이터 프레임이 있습니다.

인덱스를 단일 열 인덱스로 재설정하지 않고 다중 인덱스의 한 열을 필터링하여 행을 선택하는 방법이 있습니까?

예를 들어.

# has multi-index (A,B)
df
#can I do this? I know this doesn't work because the index is multi-index so I need to     specify a tuple

df.ix[df.A ==1]


관련 : pandas MultiIndex DataFrame에서 행을 선택하십시오 (같은 주제에 대한 광범위한 토론).
cs95

답변:


136

한 가지 방법은 get_level_valuesIndex 메서드 를 사용하는 것입니다.

In [11]: df
Out[11]:
     0
A B
1 4  1
2 5  2
3 6  3

In [12]: df.iloc[df.index.get_level_values('A') == 1]
Out[12]:
     0
A B
1 4  1

0.13에서는 인수 xs와 함께drop_level 사용할 수 있습니다 .

df.xs(1, level='A', drop_level=False) # axis=1 if columns

참고 : 이것이 인덱스가 아닌 MultiIndex 열인 경우 동일한 기술을 사용할 수 있습니다.

In [21]: df1 = df.T

In [22]: df1.iloc[:, df1.columns.get_level_values('A') == 1]
Out[22]:
A  1
B  4
0  1

53

query내 의견으로는 매우 읽기 쉽고 사용하기 쉬운 사용할 수도 있습니다.

import pandas as pd

df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [10, 20, 50, 80], 'C': [6, 7, 8, 9]})
df = df.set_index(['A', 'B'])

      C
A B    
1 10  6
2 20  7
3 50  8
4 80  9

염두에 둔 것에 대해 이제 간단히 할 수 있습니다.

df.query('A == 1')

      C
A B    
1 10  6

다음을 사용하여 더 복잡한 쿼리를 가질 수도 있습니다. and

df.query('A >= 1 and B >= 50')

      C
A B    
3 50  8
4 80  9

or

df.query('A == 1 or B >= 50')

      C
A B    
1 10  6
3 50  8
4 80  9

다른 색인 수준 에서 쿼리 할 수도 있습니다. 예 :

df.query('A == 1 or C >= 8')

돌아올 것이다

      C
A B    
1 10  6
3 50  8
4 80  9

쿼리 내에서 변수를 사용하려면 다음을 사용할 수 있습니다@ .

b_threshold = 20
c_threshold = 8

df.query('B >= @b_threshold and C <= @c_threshold')

      C
A B    
2 20  7
3 50  8

1
훌륭한 대답, 실제로 더 읽기 쉽습니다. 다음과 같이 서로 다른 인덱스 수준에서 두 필드를 쿼리 할 수 ​​있는지 아십니까?df.query('A == 1 or C >= 8')
obchardon

@obchardon : 잘 작동하는 것 같습니다. 나는 당신의 예를 사용하여 내 대답을 편집했습니다.
Cleb

1
문자열 표현식에 문제를 일으키는 다중 인덱스로 시간과 문자열이 있습니다. 그러나 환경 의 변수 에 대해 df.query()쿼리의 표현식 내에서 '@'로 참조되는 경우 변수와 잘 작동 합니다. df.query('A == @varvar
Solly

@Solly : 감사합니다, 나는 이것을 대답에 추가했습니다.
Cleb

여기서 멀티 인덱싱은 어디에 있습니까?
Lamma

32

다음을 사용할 수 있습니다 DataFrame.xs().

In [36]: df = DataFrame(np.random.randn(10, 4))

In [37]: df.columns = [np.random.choice(['a', 'b'], size=4).tolist(), np.random.choice(['c', 'd'], size=4)]

In [38]: df.columns.names = ['A', 'B']

In [39]: df
Out[39]:
A      b             a
B      d      d      d      d
0 -1.406  0.548 -0.635  0.576
1 -0.212 -0.583  1.012 -1.377
2  0.951 -0.349 -0.477 -1.230
3  0.451 -0.168  0.949  0.545
4 -0.362 -0.855  1.676 -2.881
5  1.283  1.027  0.085 -1.282
6  0.583 -1.406  0.327 -0.146
7 -0.518 -0.480  0.139  0.851
8 -0.030 -0.630 -1.534  0.534
9  0.246 -1.558 -1.885 -1.543

In [40]: df.xs('a', level='A', axis=1)
Out[40]:
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543

A수준 을 유지하려면 ( drop_level키워드 인수는 v0.13.0부터 만 사용 가능) :

In [42]: df.xs('a', level='A', axis=1, drop_level=False)
Out[42]:
A      a
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543

1
하, 방금 내 대답을 업데이트했습니다. 참고 : 0.13에서만 사용할 수 있습니다.
Andy Hayden

아, 반갑습니다. 각 버전에 어떤 작은 편의가 추가되었는지 기억이 나지 않습니다.
Phillip Cloud

Lol, 사실이 질문은 그 편리함에 영감을 준 질문의 속임수입니다! :)
Andy Hayden

13

다중 인덱싱 된 pandas DataFrame에 액세스하는 방법을 이해 하면 이와 같은 모든 종류의 작업에 도움이 될 수 있습니다.

예제를 생성하려면 코드에 붙여 넣으십시오.

# hierarchical indices and columns
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]],
                                   names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']],
                                     names=['subject', 'type'])

# mock some data
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37

# create the DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data

다음과 같은 테이블을 제공합니다.

여기에 이미지 설명 입력

열별 표준 액세스

health_data['Bob']
type       HR   Temp
year visit      
2013    1   22.0    38.6
        2   52.0    38.3
2014    1   30.0    38.9
        2   31.0    37.3


health_data['Bob']['HR']
year  visit
2013  1        22.0
      2        52.0
2014  1        30.0
      2        31.0
Name: HR, dtype: float64

# filtering by column/subcolumn - your case:
health_data['Bob']['HR']==22
year  visit
2013  1         True
      2        False
2014  1        False
      2        False

health_data['Bob']['HR'][2013]    
visit
1    22.0
2    52.0
Name: HR, dtype: float64

health_data['Bob']['HR'][2013][1]
22.0

행별 액세스

health_data.loc[2013]
subject Bob Guido   Sue
type    HR  Temp    HR  Temp    HR  Temp
visit                       
1   22.0    38.6    40.0    38.9    53.0    37.5
2   52.0    38.3    42.0    34.6    30.0    37.7

health_data.loc[2013,1] 
subject  type
Bob      HR      22.0
         Temp    38.6
Guido    HR      40.0
         Temp    38.9
Sue      HR      53.0
         Temp    37.5
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']
type
HR      22.0
Temp    38.6
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']['HR']
22.0

다중 인덱스 슬라이싱

idx=pd.IndexSlice
health_data.loc[idx[:,1], idx[:,'HR']]
    subject Bob Guido   Sue
type    HR  HR  HR
year    visit           
2013    1   22.0    40.0    53.0
2014    1   30.0    52.0    45.0

이것은 ValueError: cannot handle a non-unique multi-index!오류를 준다
Coddy

5

다음을 사용할 수 있습니다 DataFrame.loc.

>>> df.loc[1]

>>> print(df)
       result
A B C        
1 1 1       6
    2       9
  2 1       8
    2      11
2 1 1       7
    2      10
  2 1       9
    2      12

>>> print(df.loc[1])
     result
B C        
1 1       6
  2       9
2 1       8
  2      11

>>> print(df.loc[2, 1])
   result
C        
1       7
2      10

이것은 df.loc [2, 1] [ 'result']가 다중 열을 처리하는 최신 접근 방식 IMO 중 최고입니다
Michael

이것은 어떤 이유로 든 여러 정수와 함께 작동합니다. 예df.loc[0], df.loc[1]....df.loc[n]
Coddy

2

또 다른 옵션은 다음과 같습니다.

filter1 = df.index.get_level_values('A') == 1
filter2 = df.index.get_level_values('B') == 4

df.iloc[filter1 & filter2]
Out[11]:
     0
A B
1 4  1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.