매일공부

[Pandas] 데이터 재구조화 — pivot, pivot_table, melt, groupby 정리 본문

Programming/Python

[Pandas] 데이터 재구조화 — pivot, pivot_table, melt, groupby 정리

julian 2022. 10. 13. 10:01

Pivot(피봇)이란

여러 분류로 섞여 있는 행 데이터를 열 데이터로 회전시키는 것. 긴 형태(long format)의 데이터를 넓은 형태(wide format)로 바꿀 때 쓴다.

pivot()

df.pivot(index=, columns=, values=)

index와 columns 조합으로 가져올 values 값이 유일(unique) 해야 한다. 같은 조합에 값이 2개 이상 존재하면 ValueError가 발생한다.

data = pd.DataFrame({
    'cust_id': ['c1', 'c1', 'c1', 'c2', 'c2', 'c2', 'c3', 'c3', 'c3'],
    'prod_cd': ['p1', 'p2', 'p3', 'p1', 'p2', 'p3', 'p1', 'p2', 'p3'],
    'grade':   ['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B'],
    'pch_amt': [30, 10, 0, 40, 15, 30, 0, 0, 10]
})

data.pivot(index='cust_id', columns=['grade', 'prod_cd'], values='pch_amt')
data.pivot(index='grade', columns='prod_cd', values='pch_amt')

여기서 index='grade'로 두면, 같은 grade 값에 여러 cust_id가 걸리면서 (index, columns) 조합이 중복될 수 있는데, 이 경우 pivot()은 에러를 낸다. 중복이 있을 가능성이 있으면 pivot()이 아니라 pivot_table()을 써야 한다.

set_index + unstack으로도 같은 결과를 만들 수 있다

df1.set_index(["도시", "연도"])[["인구"]].unstack()

pivot()이 하는 재구조화는 사실 set_index() + unstack() 조합으로도 만들 수 있다. set_index로 여러 열을 멀티인덱스로 만든 뒤, unstack()으로 안쪽 인덱스 레벨을 열 방향으로 펼치는 방식.

pivot_table() — 중복값이 있어도 안전

df.pivot_table(data=, values=, index=, columns=, aggfunc=, fill_value=, margins=)

pivot()과 목적은 같지만, 같은 (index, columns) 조합에 값이 여러 개 있어도 에러 없이 처리된다. aggfunc(예: np.sum, np.mean) 같은 집계 함수로 중복된 값들을 하나로 합쳐주기 때문 — 사실상 pivot() + groupby가 합쳐진 형태다.

  • margins=True: 행/열 기준 합계(All, row sum, column sum)를 결과에 함께 출력해준다

melt() — pivot의 반대 방향 (wide → long)

pd.melt(data, id_vars=, var_name=, value_name=)

넓은 형태의 데이터를 다시 긴 형태로 되돌리는 함수다. id_vars로 지정한 기준 열은 그대로 두고, 나머지 여러 열의 이름들을 variable 칼럼(또는 var_name으로 지정한 이름)에 위에서 아래로 길게 쌓아놓고, 그 각각에 대응하는 값을 value 칼럼(value_name)에 채워 넣는 방식으로 데이터를 재구조화한다.

melt()와 pivot_table()의 결과 구조 차이: melt()의 결과에서는 ID가 일반 칼럼으로 생성되는 반면, pivot_table()의 결과에서는 ID가 index로 생성된다.

그 외 자주 쓰는 집계/카운트 함수

df['열이름'].count(dropna=True)        # 결측치 제외 개수 확인
df['열이름'].value_counts(dropna=True)  # 고유값별 개수

groupby()

df.iloc[:, [0, 2, 5]].groupby('열이름').agg(['sum', 'mean'])

연산대상.groupby(그룹핑 기준) 형태로 쓴다. groupby()만 실행한 결과는 내부적으로 그룹별로 나뉜 상태(개념적으로 딕셔너리에 가까움)일 뿐 바로 값을 보여주지 않는다 — "그룹핑이 된 GroupBy 객체가 생성됐다"는 것만 확인할 수 있고, 여기에 .agg(), .sum(), .mean() 같은 집계 함수를 이어 붙여야 실제 결과가 나온다.

정리 — 언제 뭘 쓰나

상황 함수

행→열 회전, (index, columns) 조합이 확실히 유일함 pivot()
행→열 회전, 중복 가능성 있어서 집계가 필요함 pivot_table()
넓은 형태를 다시 긴 형태로 되돌리고 싶음 melt()
특정 기준으로 묶어서 집계만 하고 싶음 (재구조화 없이) groupby()
Comments