Python Pandas : Multi index 없애기, 다중 column 없애기, multi column 없애기
Pandas를 통해서 데이터를 다루다 보면 간혹 multi index가 생기는 경우가 있습니다.
특히 pivot_table() method를 사용한 후에 자주 발생하는데 이런 경우는 사실 다루기가 마냥 좋은 상태는 아닙니다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
print(df_test)
-- Result
number string
date item item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
multi index가 무엇인지 모르는 분들을 위해 multi index를 가진 DataFrame을 만들어봤습니다.
위 예시의 결과를 보면 column 이름을 표시하는 부분이 2줄로 되어있는 것을 알 수 있습니다.
number string
date item item_name
이렇게 column name이 두줄로 표시되어 있습니다.
어쨌든 DataFrame의 최종 column 개수는 3개인데 각 column의 표시가 2중으로 되어있다는 것이죠.
실제 이론상 2중, 3중, 4중, ... 등등의 column name 표시가 가능합니다.
이런 상태를 multi index 또는 multi column이라고 합니다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
print(df_test.columns)
-- Result
MultiIndex([('number', 'date'),
('number', 'item'),
('string', 'item_name')],
)
그래서 이런 multi index DataFrame의 columns를 print해보면 위처럼 하나의 column에 대해 2개의 index가 tuple로 묶인 채로 표시됩니다.
이런 경우에 multi index를 없애고 single index로 만들면 다루기 더 쉬워지는 경우가 있습니다.
위같은 multi index를 없애는 방법은 여러 가지가 있는데 그 중 몇가지만 알아봅시다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
df_test = df_test.droplevel(level=0, axis=1)
print(df_test)
-- Result
date item item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
droplevel() method를 사용하는 예시입니다.
결과부터 보면 각 column의 이름이 1줄로만 표시되는 것을 볼 수 있죠.
df_test = df_test.droplevel(level=0, axis=1)
핵심은 이 부분입니다.
droplevel()은 이름에서도 볼 수 있듯이 level (계층)을 drop하는 기능을 합니다.
여기서 level=0이라고 명시했는데
number string --> level 0 index
date item item_name --> level 1 index
이러한 multi index에서 더 위쪽에 있는 것이 level = 0이고
더 아래에 갈수록 level이 커집니다.
따라서 droplevel()에서 level=0으로 적었다는 것은 위쪽에 있는 level 0 index를 없애겠다는 의미입니다.
그래서 결과에는 date, item, item_name 3개의 column name만 남은 것을 볼 수 있죠.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
df_test = df_test.droplevel(level=1, axis=1)
print(df_test)
-- Result
number number string
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
반대로 level=1로 명시할 경우 아래쪽 줄에 있던 column name이 다 사라지고 위쪽(level=0)에 있던 column name만 남은 것을 알 수 있습니다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
print(df_test.columns)
print(df_test.columns.droplevel(level=0))
df_test.columns = df_test.columns.droplevel(level=0)
print(df_test)
-- Result
MultiIndex([('number', 'date'),
('number', 'item'),
('string', 'item_name')],
)
Index(['date', 'item', 'item_name'], dtype='object')
date item item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
두 번째 방법도 droplevel()을 이용하나 좀 다른 방식으로 이용하는 것입니다.
MultiIndex([('number', 'date'),
('number', 'item'),
('string', 'item_name')],
)
multi index를 출력해보면 위와 같습니다.
여기서 level=0 column은 number와 string입니다.
(이걸 보면 왜 위쪽에 명시된 컬럼이 level=0인지 알 수 있죠. tuple의 첫 번째 자리 즉, tuple의 index=0 자리에 명시되기 때문에 level=0 column이 되는 것입니다.)
df_test.columns.droplevel(level=0)
그리고 이런식으로 columns 속성에 있는 level=0 위치에 있는 level을 모두 drop하면
Index(['date', 'item', 'item_name'], dtype='object')
level=0 은 다 사라지고 level=1이었던 column name만 남게 됩니다.
- df_test.columns = df_test.columns.droplevel(level=0)
이렇게 level=1 column만 남은 column name 정보를 df_test.columns 속성에 덮어씌우는 것입니다.
이런식으로 기존 multi index DataFrame의 column 정보를 덮어씌워서 multi index를 제거하는 방법이 있습니다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
df_test.columns = ['date', 'item', 'item_name']
print(df_test)
-- Result
date item item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
방금 전에 설명했던 방식과 비슷하게 multi index를 가지고 있는 DataFrame의 columns 속성에
내가 원하는 column 이름을 list의 형태로 전달하여 덮어 씌우는 것입니다.
MultiIndex([('number', 'date'),
('number', 'item'),
('string', 'item_name')],
)
아까 위에서 multi index의 column은 위처럼 tuple로 묶인 형태로 표시된다는 것을 알면 이것을 이용하여 다양한 방법을 사용할 수 있습니다.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
df_test.columns = [col[1] for col in df_test.columns]
print(df_test)
-- Result
date item item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
이런 식으로 columns 속성을 참조하고
거기서 tuple 내에 index = 1위치에 있는 값으로만 list를 구성합니다.
그리고 df_test의 columns를 덮어씌우면 multi index가 제거되는 것이죠.
import pandas as pd
multi_cols = pd.MultiIndex.from_tuples(
[
('number', 'date'),
('number', 'item'),
('string', 'item_name')
]
)
df_test = pd.DataFrame(
[
(20230101, 1, 'a'),
(20230101, 2, 'b'),
(20230101, 3, 'c'),
(20230102, 1, 'a'),
(20230102, 3, 'c'),
(20230103, 2, 'b'),
(20230103, 4, 'd'),
],
columns=multi_cols
)
df_test.columns = ['_'.join(col) for col in df_test.columns]
print(df_test)
-- Result
number_date number_item string_item_name
0 20230101 1 a
1 20230101 2 b
2 20230101 3 c
3 20230102 1 a
4 20230102 3 c
5 20230103 2 b
6 20230103 4 d
이제 감이 오시나요.
위같은 방법도 존재합니다.
그래서 multi index는 DataFrame의 columns 속성 내에서
하나의 column에 대한 multi index가 tuple에 묶여서 존재한다는 사실만 안다면 이를 다양하게 이용할 수 있습니다.