[Python pandas] 데이터 재구조화(reshaping data) : pd.DataFrame.stack(), pd.DataFrame.unstack()
Python 분석과 프로그래밍/Python 데이터 전처리 2016. 12. 24. 23:29데이터 재구조화(reshaping data)를 위해 사용할 수 있는 Python pandas의 함수들에 대해서 아래의 순서대로 나누어서 소개해보겠습니다.
- (1) pivot(), pd.pivot_table()
- (2) stack(), unstack()
이번 포스팅에서는 두번째로 pd.DataFrame.stack(), pd.DataFrame.unstack()에 대해서 알아보겠습니다.
stack을 영어사전에서 찾아보면 뜻이
stack[stӕk]~ (sth) (up) (깔끔하게 정돈하여) 쌓다[포개다]; 쌓이다, 포개지다
~ sth (with sth) (어떤 곳에 물건을 쌓아서) 채우다
라는 뜻입니다.
stack이 (위에서 아래로 길게, 높게) 쌓는 것이면, unstack은 쌓은 것을 옆으로 늘어놓는것(왼쪽에서 오른쪽으로 넓게) 라고 연상이 될 것입니다.
Python pandas의 stack(), unstack() 실습에 필요한 모듈을 불러오고, 예제로 사용할 hierarchical index를 가진 DataFrame을 만들어보겠습니다.
In [1]: import numpy as np In [2]: import pandas as pd In [3]: from pandas import DataFrame In [4]: mul_index = pd.MultiIndex.from_tuples([('cust_1', '2015'), ('cust_1', '2016'), ...: ('cust_2', '2015'), ('cust_2', '2016')]) ...: In [5]: data = DataFrame(data=np.arange(16).reshape(4, 4), ...: index=mul_index, ...: columns=['prd_1', 'prd_2', 'prd_3', 'prd_4'], ...: dtype='int') ...: In [6]: data Out[6]: prd_1 prd_2 prd_3 prd_4
|
stack() method 를 사용해서 위의 예제 데이터셋을 위에서 아래로 길게(높게) 쌓아(stack) 보겠습니다. 칼럼의 level은 1개 밖에 없으므로 stack(level=-1) 을 별도로 명기하지 않아도 됩니다.
(1) pd.DataFrame.stack(level=-1, dropna=True) |
DataFrame을 stack() 후에 index를 확인해보고, indexing 해보겠습니다.
DataFrame을 stack() 하면 Series 를 반환합니다.
# stack() In [7]: data_stacked = data.stack()
# DataFrame.stack() => returns Series In [8]: data_stacked Out[8]: cust_1 2015 prd_1 0 dtype: int32
In [9]: data_stacked.index Out[9]: MultiIndex(levels=[['cust_1', 'cust_2'], ['2015', '2016'], ['prd_1', 'prd_2', 'prd_3', 'prd_4']], labels=[[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1], [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1], [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]])
In [10]: data_stacked['cust_2']['2015'][['prd_1', 'prd_2']] Out[10]: prd_1 8 prd_2 9 dtype: int32
|
결측값이 있는 데이터셋을 stack() 할 때 결측값을 제거할지(dropna=True), 아니면 결측값을 NaN으로 유지할지(dropna=False) 설정할 수 있는 stack(dropna=True, False)를 예를 들어 설명해보겠습니다.
# # putting NaN to DataFrame In [11]: data.ix['cust_2', 'prd_4'] = np.nan In [12]: data Out[12]: prd_1 prd_2 prd_3 prd_4
In [13]: data.stack(dropna=False) Out[13]: cust_1 2015 prd_1 0.0 dtype: float64
In [14]: data.stack(dropna=True) # by default Out[14]: cust_1 2015 prd_1 0.0 dtype: float64
|
stack()으로 위에서 아래로 길게(높게) 쌓아 올린 데이터셋을 이번에는 거꾸로 왼쪽으로 오른쪽으로 넓게 unstack()으로 풀어보겠습니다.
stack() 후의 data_stacked 데이터셋이 아래에 보는 것처럼 level이 3개 있는 MultiIndex 입니다. 이럴 경우 unstack(level=-1), unstack(level=0), unstack(level=1) 별로 어떤 level이 칼럼으로 이동해서 unstack() 되는지 유심히 살펴보시기 바랍니다.
(2) pd.DataFrame.unstack(level=-1, fill_value=None) |
In [15]: data_stacked Out[15]: cust_1 2015 prd_1 0 dtype: int32 In [16]: data_stacked.unstack(level=-1) Out[16]: prd_1 prd_2 prd_3 prd_4 In [17]: data_stacked.unstack(level=0) Out[17]: cust_1 cust_2
In [18]: data_stacked.unstack(level=1) Out[18]: 2015 2016
|
unstack() 한 후의 데이터셋도 역시 Series 인데요, 이것을 DataFrame으로 변환해보겠습니다.
# converting Series to DataFrame In [19]: data_stacked_unstacked = data_stacked.unstack(level=-1) In [20]: data_stacked_unstacked Out[20]: prd_1 prd_2 prd_3 prd_4
# converting index to columns In [21]: data_stacked_unstacked_df = data_stacked_unstacked.reset_index()
# changing columns' name In [22]: data_stacked_unstacked_df.rename(columns={'level_0' : 'custID', ...: 'level_1' : 'year'}, inplace=True) ...: In [23]: data_stacked_unstacked_df Out[23]: custID year prd_1 prd_2 prd_3 prd_4
|
이상으로 stack(), unstack()을 이용한 데이터 재구조화에 대해서 알아보았습니다.
다음번 포스팅에서는 melt(), wide_to_long() 을 이용한 데이터 재구조화를 소개하겠습니다.
많은 도움 되었기를 바랍니다.
댓글을 달아 주세요
항상 유용하고 꾸준한 포스팅 감사드립니다. 실무에 이부분을 적용하던찰나에 막히는 부분이 있어서 이부분에서 질문하나 드려도 될까요?
현재 stack에서 unstack을 반환하기전에, stack을 통한 데이터프레임이 pivot_table과 흡사한 것 같습니다. 그런데 이러한 프레임에 아래와 같이 추가로 계산된 열을 삽입하려면, 어떻게 해야하는지 문의드립니다. 물론 예제의 데이터는 인덱스가 많지않은데 cust_3,cust_4 계속이어질 경우 이에 대한 코드는 하나의 성장율 row를 만든 후, 반복문을 통해 구성하는지도 문의드려 봅니다.
| | | prd1 | prd2 | prd3 | prd4 |
| cust_1| 2015 | 0 | 1 | 2 | 3 |
| | 2016 | 4 | 5 | 6 | 7 |
| cust_2| 2015 | 8 | 9 | 10 | 11 |
| | 2016 | 12 | 13 | 14 | 15 |
| GR% | 2015 | Nan | 800% | 400% |266.7%|
| | 2016 | 200% |160.0%|133.3%|114.3%|
안녕하세요 chapchu 님,
DataFrame의 각 칼럼에는 동일한 데이터 유형의 값이 들어가야 합니다. 그런데 질문에 남겨주신 내용을 보면 첫번째 칼럼에는 문자형과 숫자형이 섞여있고, 두번째 칼럼에는 숫자형과 백분율 유형의 값이 섞여있습니다.
제 생각에는 성장율(%)의 경우 질문주신 것처럼 row를 밑에 계속 append 해서 붙이기 보다는 오른쪽으로 새로운 칼럼을 넣는게 좋을 것 같습니다.
아래 블로그 포스팅이 그룹별로 이전 분기/ 전년 동분기 대비 변동율에 대한 포스팅인데요, 참고가 될 것 같습니다.
https://rfriend.tistory.com/590