Python Library/Pandas

[Pandas - Python] Hierarchical Indexing (계층적 인덱싱)

바보1 2022. 6. 14. 02:13

Hierarchical Indexing

 

계층적 인덱싱이란,

a라는 인덱스 안에 1, 2, 3이라는 인덱스가 있고,

c라는 인덱스 안에 또 1, 2, 3가 있는 그런 형태입니다.

 

예를 들어 홍길동이라는 이름이 있다고 가정해봅시다.

물론 남자 같은 이름이지만 여자가 있을 수도 있습니다.

 

남자 인덱스 안에 [홍길동, 24] 이런 식으로 넣고, 여자 인덱스 안에 [홍길동, 23] 이런 식으로 넣을 수 있습니다.

 

이때 사용하는 것이 Hierarchical Indexing 입니다.

 

 

data = pd.Series(np.random.randn(9),
                 index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'],
                        [1, 2, 3, 1, 3, 1, 2, 2, 3]])
data

a  1   -0.204708
   2    0.478943
   3   -0.519439
b  1   -0.555730
   3    1.965781
c  1    1.393406
   2    0.092908
d  2    0.281746
   3    0.769023
dtype: float64

이해가 되시나요?

 

이때 index를 추출하면,

data.index

MultiIndex([('a', 1),
            ('a', 2),
            ('a', 3),
            ('b', 1),
            ('b', 3),
            ('c', 1),
            ('c', 2),
            ('d', 2),
            ('d', 3)],
           )

이렇게 나옵니다.

 

최상단 Index(level = 0)를 기준으로 loc 등의 함수를 사용할 수 있습니다.

 

이때 level 1에서 인덱스가 2인 row를 추출하고 싶다면,

data.loc[:, 2]

a    0.478943
c    0.092908
d    0.281746
dtype: float64

이렇게 사용하면 간단하게 추출할 수 있습니다.

 

위의 데이터는 Series Data이지만, 이를 unstack() 함수를 이용하여 DataFrame 형태로 변환할 수 있습니다.

data.unstack()

	1		2		3
a	-0.204708	0.478943	-0.519439
b	-0.555730	NaN		1.965781
c	1.393406	0.092908	NaN
d	NaN		0.281746	0.769023

이를 또 다시 stack() 함수를 이용하여 Series 형태로 변환할 수 있습니다.

data.unstack().stack()

a  1   -0.204708
   2    0.478943
   3   -0.519439
b  1   -0.555730
   3    1.965781
c  1    1.393406
   2    0.092908
d  2    0.281746
   3    0.769023
dtype: float64

 

 

만약 DataFrame 형태로 사용하고, Column에도 계층적 인덱싱을 적용하고 싶다면, 아래와 같이 하면 됩니다.

frame = pd.DataFrame(np.arange(12).reshape((4, 3)),
                     index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]],
                     columns=[['Ohio', 'Ohio', 'Colorado'],
                              ['Green', 'Red', 'Green']])
frame

		Ohio		Colorado
		Green	Red	Green
a	1	0	1	2
	2	3	4	5
b	1	6	7	8
	2	9	10	11

이때도 name을 설정할 수 있는데, 이때는 리스트 형태로 각각 넣어줘야 합니다.

frame.index.names = ['key1', 'key2']
frame.columns.names = ['state', 'color']
frame

        state	Ohio		Colorado
        color	Green	Red	Green
key1	key2			
a	1	0	1	2
	2	3	4	5
b	1	6	7	8
	2	9	10	11

이때 Ohio 주만 추출하면,

frame['Ohio']

	color	Green	Red
key1	key2		
a	1	0	1
  	2	3	4
b	1	6	7
   	2	9	10

이렇게 깔끔하게 Ohio 주만 추출합니다.

 

 

 

만약에 key1과 key2의 레벨을 바꾸고 싶다면, swaplevel() 함수를 이용하면 됩니다.

frame.swaplevel('key1', 'key2')

	state	Ohio		Colorado
	color	Green	Red	Green
key2	key1			
1	a	0	1	2
2	a	3	4	5
1	b	6	7	8
2	b	9	10	11

 

 

기존의 frame에서 레벨 1을 기준으로 정렬하면 어떻게 될까요?

frame.sort_index(level=1)


	state	Ohio		Colorado
	color	Green	Red	Green
key1	key2			
a	1	0	1	2
b	1	6	7	8
a	2	3	4	5
b	2	9	10	11

이렇게 key2를 기준으로 정렬하게 됩니다.

 

혹은 기존의 frame에서 level 0과 level 1의 위치를 바꾼 후, level 0에 대해 정렬하면 어떻게 될까요?

frame.swaplevel(0, 1).sort_index(level=0)

	state	Ohio		Colorado
	color	Green	Red	Green
key2	key1			
1	a	0	1	2
        b	6	7	8
2	a	3	4	5
        b	9	10	11

 

참고로 기존의 frame은 아래와 같습니다.

	state	Ohio		Colorado
	color	Green	Red	Green
key1	key2			
a	1	0	1	2
        2	3	4	5
b	1	6	7	8
        2	9	10	11

 

참고로 key2를 기준으로 sum 함수를 적용할 수도 있습니다.

frame.sum(level='key2')


state	Ohio	Colorado
color	Green	Red	Green
key2			
1	6	8	10
2	12	14	16

key2가 1인 row와 key2가 2인 row끼리 더합니다.

 

다른 방식으로 color를 기준으로 더할 수도 있습니다.

frame.sum(level='color', axis=1)

	color	Green	Red
key1	key2		
a	1	2	1
        2	8	4
b	1	14	7
        2	20	10

참고로 axis = 0으로 하면 오류가 발생합니다.