오늘 할 일: 끝내주게 숨쉬기
article thumbnail

데이터 분석을 하다보면 필요에 따라 기존에 구성되어 있는 데이터를 재구조화하기도 합니다. 본 포스팅에서는 파이썬에서 데이터프레임을 재구성하는 방법, 특히 wide하게 구성되어 있는 데이터를 long하게 변경하는 방법에 대해 알아보겠습니다. wide 데이터는 가로로 놓여진 데이터를, long 데이터는 세로로 늘어놓인 데이터라는 것을 이해하고 읽으시면 좋겠습니다.

 

사용할 데이터는 다음과 같습니다. 

import pandas as pd
df = pd.DataFrame({"id" : ['a', 'b', 'c'],
                   "pred1" : [0.5, 0.6, 0.8],
                   "pred2" : [0.8, 0.6, 0.4],
                   "pred3" : [0.2, 0.7, 0.5]})
display(df)

unique한 아이디마다 세 종류의 예측값이 붙어있는 wide 데이터입니다. 위 데이터프레임에서 wide하게 있던 pred1, pred2, pred3 칼럼을 long한 포맷이 되도록 변경해보겠습니다.

 

 

pd.wide_to_long()

 

wide 데이터를 long 데이터로 변경하는 첫번째 방법은 pandas의 wide_to_long 함수를 이용하는 방법입니다. 파라미터는 아래와 같습니다.

  • df: pd.DataFrame
  • stubnames: 아래로 펼칠 칼럼명의 공통 문자. 이 문자로 시작하는 칼럼들을 long하게 늘여놓겠다! 이런 의미입니다.
  • i: 인덱스로 사용할 칼럼
  • j: 공통문자 다음에 오는 값이 저장될 칼럼명
pd.wide_to_long(df, ["pred"], i="id", j="model")

칼럼이었던 pred1, pred2, pred3을 아래로 늘여놓았습니다. pred 다음에 붙어있던 숫자들은 model이란 이름을 갖는 인덱스로 long하게 포맷이 변경되었습니다. 그리고 인덱스 id, model 값의 조합에 따라 pred의 값이 옮겨와진 것을 확인할 수 있습니다.

 

long하게 변경할 변수명이 구분자와 문자를 포함한다면 sep(구분자 지정), suffix(정규표현식 적용) 파라미터를 이용합니다.

df = pd.DataFrame({"id" : ['a', 'b', 'c'],
                   "pred_rf" : [0.5, 0.6, 0.8],
                   "pred_lgb" : [0.8, 0.7, 0.4],
                   "pred_xg" : [0.2, 0.7, 0.5]})

display(df, pd.wide_to_long(df, ["pred"], i="id", j="model", sep='_', suffix=r'\w+'))

왼쪽에 wide하게 있던 pred_rf, pred_lgb, pred_xg 칼럼들을 long하게 오른쪽처럼 변경하였습니다.

suffix에서 사용한 정규표현식에 대해 자세하게 알고싶으신 분은 구글에 '파이썬 정규표현식'이라고 검색하셔서 공부해보시길 추천합니다!

 

만약 long하게 바꾼 데이터를 다시 wide하게 변경하고 싶다면, unstack 메소드를 이용합니다.

l = pd.wide_to_long(df, ["pred"], i="id", j="model", sep='_', suffix=r'\w+')
w = l.unstack()
w.columns = w.columns.map('{0[0]}_{0[1]}'.format)
display(w)

 

 

pd.melt()

 

wide 데이터를 long 데이터로 변경하는 두번째 방법은 melt 함수를 이용하는 방법입니다. 여기서 사용할 파라미터는 아래와 같습니다.

  • df: pd.DataFrame
  • id_vars: 식별자로 사용할 기준 칼럼
  • value_vars: long하게 변경할 현재 wide한 칼럼들. 사용자가 지정하지 않는 경우 id_vars를 제외한 모든 칼럼으로 설정됩니다.
  • 더 다양한 파라미터는 공식 문서를 참고하세요
df_long = pd.melt(df, id_vars=['id'], value_vars=['pred_lgb', 'pred_rf', 'pred_xg']).sort_values('id')
display(df_long)

melt 함수를 이용하여 long하게 데이터를 재구조화하고, id 칼럼으로 정렬했습니다. 새로 생긴 variable 칼럼과 value 칼럼을 살펴보겠습니다. variable 칼럼에는 long하게 변경하려고 지정했던 칼럼들의 이름이 값으로 들어가 있습니다. value 칼럼에는 id와 variable의 조합에 따른 값이 들어가 있구요.

 

추가로 rank 함수를 이용해 id마다 rf, lgb, xg 중 어떤 모델의 예측값(pred)이 가장 큰지 순위를 매겨보고, pivot 메소드를 이용해 순위에 따라 모델명을 정렬해보며 글을 마치겠습니다.

df_long['rank'] = df_long.groupby('id')['value'].rank(ascending=False, method='first')
df_long2wide = df_long.pivot(index='id', columns='rank')['variable']

display(df_long2wide)

 

 

참고

 

https://pandas.pydata.org/docs/reference/api/pandas.wide_to_long.html

 

pandas.wide_to_long — pandas 1.3.2 documentation

A regular expression capturing the wanted suffixes. ‘\d+’ captures numeric suffixes. Suffixes with no numbers could be specified with the negated character class ‘\D+’. You can also further disambiguate suffixes, for example, if your wide variables

pandas.pydata.org

https://pandas.pydata.org/docs/reference/api/pandas.melt.html

 

pandas.melt — pandas 1.3.2 documentation

If True, original index is ignored. If False, the original index is retained. Index labels will be repeated as necessary.

pandas.pydata.org

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.unstack.html

 

pandas.DataFrame.unstack — pandas 1.3.2 documentation

Level(s) of index to unstack, can pass level name.

pandas.pydata.org