Pandas - [5단계] 판다스 데이터 결합/변형

c.haha.e·2025년 8월 12일

STUDY

목록 보기
7/27

판다스 데이터 결합/변형


1. 데이터 이어붙이기 (concat)

  • 수직/수평으로 단순하게 데이터프레임을 연결
  • SQL의 UNION ALL과 비슷
  • 인덱스/컬럼 이름이 같아야 자동 정렬됨

(1) 기본 사용법

import pandas as pd

df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})

# 위아래로(행방향) 붙이기 (default axis=0)
result = pd.concat([df1, df2])
print(result)
#    A  B
# 0  1  3
# 1  2  4
# 0  5  7
# 1  6  8

# 좌우로(열방향) 붙이기
result2 = pd.concat([df1, df2], axis=1)
  • 인덱스가 중복될 수 있음. → ignore_index=True로 새 인덱스 부여 가능
    • ignore_index=True vs reset_index() vs set_index() 차이

      1. 세 가지 핵심 요약

      비교ignore_index=Truereset_index()set_index()
      어디서 씀?sort_values(), concat(), drop_duplicates(), groupby().apply()DataFrame 메서드DataFrame 메서드
      역할기존 인덱스 버리고 0부터 새 인덱스 부여현재 인덱스를 컬럼으로 복구하고 0부터 새 인덱스 부여특정 컬럼을 인덱스로 설정
      기존 인덱스완전 삭제됨컬럼으로 이동 (drop=True면 삭제)기존 인덱스는 대체됨
      주요 옵션ignore_index=Truedrop=True (컬럼 버릴지 말지)drop=False (컬럼 남길지)
      주 용도정렬/합치기 후 인덱스 새로 부여다중 인덱스 풀기, 초기화기준 잡고 정리 정렬할 때

      세 가지 쉽게 비유하면

      • ignore_index=True : → "너네 인덱스 다 버리고 0부터 새로 번호 매길게."
      • reset_index() : → "현재 인덱스를 컬럼으로 꺼내서, 기본 인덱스(0,1,2...)로 초기화할게."
      • set_index() : → "이 컬럼을 새 인덱스로 삼을게."
  • 컬럼/행이 없는 경우 자동 NaN

2. 데이터 병합하기 (merge)

  • SQL의 JOIN과 완전히 동일
  • 두 데이터프레임에서 공통 컬럼(키)을 기준으로 합침

(1) 기본 사용법

left = pd.DataFrame({'key': ['A', 'B', 'C'], 'val1': [1, 2, 3]})
right = pd.DataFrame({'key': ['B', 'C', 'D'], 'val2': [4, 5, 6]})

result = pd.merge(left, right, on='key', how='inner')
print(result)
#   key  val1  val2
# 0   B     2     4
# 1   C     3     5
  • how 옵션: 'inner'(교집합), 'outer'(합집합), 'left', 'right'

(2) 키(컬럼명) 다를 때

pd.merge(left, right, left_on='key', right_on='id')

(3) 여러 컬럼 기준 병합

pd.merge(df1, df2, on=['A', 'B'])

(4) 중복 컬럼 자동 접미사

pd.merge(df1, df2, on='A', suffixes=('_left', '_right'))
옵션설명
on='컬럼명'두 데이터프레임에서 공통 키를 직접 지정
left_on='컬럼명1', right_on='컬럼명2'df1, df2에서 다른 컬럼을 기준으로 합칠 때
how='inner', 'left', 'right', 'outer'어떤 방식으로 합칠지 (SQL의 JOIN 개념)
suffixes=('_left', '_right')겹치는 컬럼명에 접미어 붙이기

3. join 메서드

  • 인덱스를 기준으로 병합
  • merge보다 간단하게 쓸 때
  • DataFrame 메서드임
df1 = df1.set_index('A')
df2 = df2.set_index('A')
joined = df1.join(df2, lsuffix='_1', rsuffix='_2')
  • 기본은 left join

4. combine_first

  • 두 데이터프레임을 겹치는 부분은 첫 번째, 나머지는 두 번째 값으로 보완
  • 결측치(NaN) 보정에 유용
df1 = pd.DataFrame({'A': [1, np.nan], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
df1.combine_first(df2)
  • df1의 결측치(NaN)만 df2 값으로 채움

5. melt (와이드 ↔ 롱 변환)

  • Wide(가로) 형태 ↔ Long(세로) 형태 변환
  • tidy data(분석/시각화/머신러닝 전처리의 핵심!)
  • 반대: pivot
df = pd.DataFrame({
    'id': [1, 2],
    'math': [90, 80],
    'eng': [85, 75]
})

melted = pd.melt(df, id_vars=['id'], value_vars=['math', 'eng'],
                 var_name='subject', value_name='score')
print(melted)
#    id subject  score
# 0   1   math     90
# 1   2   math     80
# 2   1    eng     85
# 3   2    eng     75

6. pivot / pivot_table

  • 행/열을 자유롭게 바꿔서 새로운 표 만들기
  • 피벗(pivot): 단일 집계
  • 피벗테이블(pivot_table): 다중 집계(aggfunc), 결측치 처리, 더 강력!
# pivot: 하나의 행/열 조합에 값이 1개만 있을 때!
pivoted = df.pivot(index='id', columns='subject', values='score')

# pivot_table: 중복, 집계 다 가능
pt = pd.pivot_table(melted, index='id', columns='subject', values='score', aggfunc='mean')

7. update

  • 동일 인덱스/컬럼에 대해 데이터만 "덮어쓰기"
df1.update(df2)
# df2에 있는 값으로 df1의 값 일부를 바로 덮어씀

8. append (concat과 거의 동일, 최신판다스에서는 concat 권장)

# 행 추가 (Deprecated, concat 사용 권장)
df1.append(df2, ignore_index=True)
# 최신 권장
pd.concat([df1, df2], ignore_index=True)

9. merge_asof (근사 병합, 시계열 데이터에서 많이 사용)

  • 값이 정확히 일치하지 않는 시계열 데이터끼리 "가장 가까운 값"끼리 병합
pd.merge_asof(left, right, on='시간', direction='nearest')

10. groupby, groupby.apply도 변형에 쓰임

  • groupby와 agg/transform/apply로 구조를 바꿀 수 있음
  • groupby / groupby.agg / groupby.transform / groupby.apply 활용 정리

    1. groupby()

    • 특정 컬럼(또는 컬럼들) 값에 따라 데이터프레임을 “그룹”으로 나눔

    • 나눈 그룹별로 집계/연산/구조변환 가능


      2. agg()

    • 여러 집계함수를 한 번에 그룹별로 적용

    • 컬럼별로 다른 집계도 가능

      df.groupby('성별').agg({'점수':['mean','max'], '나이':'min'})

      3. transform()

    • 그룹별로 집계값을 “원본 데이터 크기”로 다시 펼쳐줌

    • 파생컬럼(예: 그룹별 평균, 그룹별 총합 등)을 만들 때 아주 많이 씀

      df['성별_평균'] = df.groupby('성별')['점수'].transform('mean')
      df['성별_총합'] = df.groupby('성별')['점수'].transform('sum')
    • 원본 데이터 행 개수 그대로, 각 행에 맞는 그룹의 값이 “매핑”되어 들어감


      4. apply()

    • 그룹별로 임의의(커스텀) 함수를 적용해서, 그룹별로 결과를 자유롭게 만들 수 있음

    • 집계뿐만 아니라, 각 그룹의 구조/형태를 “자유자재”로 변환할 수 있음

      def top2(grp):
          return grp.nlargest(2, '점수')
      df.groupby('학년').apply(top2)
    • → 각 학년별로 점수 top2만 남김 (그룹별 복잡한 변형/가공 가능)


      5. 활용 예시

    • 그룹별 통계/순위/파생변수 생성

      • (예: 반별 평균, 직군별 최고 연봉, 상품별 판매비율 등)
    • 그룹별 구조 변환, 여러 단계의 계층 구조를 다루기

    • groupby와 melt/pivot/stack/unstack을 조합해서 데이터 모양을 자유자재로 바꿈


      6. 예시 코드

      import pandas as pd
      df = pd.DataFrame({
          '반': ['A', 'A', 'B', 'B', 'C'],
          '학생': ['홍', '이', '박', '최', '정'],
          '점수': [90, 85, 70, 95, 80]
      })
      
      # 반별 평균점수 컬럼
      df['반평균'] = df.groupby('반')['점수'].transform('mean')
      
      # 반별 최고점만 남기는 데이터프레임
      def 최고점(grp):
          return grp[grp['점수'] == grp['점수'].max()]
      top = df.groupby('반').apply(최고점).reset_index(drop=True)

      7. groupby → 구조변형

    • groupby-agg로 집계 → pivot/unstack/reset_index 등으로 표 구조까지 변형 가능

      table = df.groupby(['반', '학생'])['점수'].sum().unstack(fill_value=0)
    • 이런 형태로:

      | 학생 | 홍 | 이 | 박 | 최 | 정 |
      | --- | --- | --- | --- | --- | --- |
      | A | 90 | 85 | 0 | 0 | 0 |
      | B | 0 | 0 | 70 | 95 | 0 |
      | C | 0 | 0 | 0 | 0 | 80 |

      8. 실전 팁

    • 실무 집계/변형/피처엔지니어링의 90%가 groupby/agg/transform/apply에서 끝난다!

    • 집계, 파생컬럼, 그룹별 비율/순위, 그룹 조건필터, 다중 인덱스 등 모두 이 조합으로 해결


      정리

    • groupby/agg/transform/apply는 EDA/분석/전처리/특성 엔지니어링/구조변환까지


정리 표

기능함수/메서드대표 예시/설명
수직/수평 연결concatpd.concat([df1, df2], axis=0/1)
SQL식 병합mergepd.merge(df1, df2, on='col', how='inner')
인덱스 병합joindf1.join(df2, lsuffix, rsuffix)
결측치 채움combine_firstdf1.combine_first(df2)
행/열 변환stack, unstackdf.stack(), df.unstack()
와이드<->롱melt, pivot, pivot_tablepd.melt(), pd.pivot(), pd.pivot_table()
값 덮어쓰기updatedf1.update(df2)
근사 병합merge_asofpd.merge_asof(df1, df2, on='date')

📝 실무 팁

  • 실전에서는 concat(단순합치기)와 merge(SQL JOIN)가 거의 필수!

  • 데이터 구조를 자유자재로 바꾸려면 melt, pivot, stack/unstack 연습이 중요

  • combine_first로 결측치 보완, update로 특정 값만 덮어쓰기 등도 실전에서 자주 등장

  • melt, pivot, stack, unstack 정리

    1. melt

    ● 목적

    • Wide(가로) 데이터 → Long(세로) 데이터로 변환

    • 머신러닝, tidy data, 시각화, groupby 등에서 '길쭉한 형태' 필요할 때 사용

      ● 기본 구조

      Before (wide):

      idmatheng
      19080
      27060

      After (long):

      idsubjectscore
      1math90
      2math70
      1eng80
      2eng60

      ● 사용법

      import pandas as pd
      df = pd.DataFrame({
          'id': [1, 2],
          'math': [90, 70],
          'eng': [80, 60]
      })
      
      melted = pd.melt(df, id_vars=['id'], value_vars=['math','eng'],
                       var_name='subject', value_name='score')
      print(melted)
    • id_vars: 그대로 남길 컬럼(식별자)

    • value_vars: 녹일 컬럼(여러 열 → 한 열)

    • var_name, value_name: 새 컬럼 이름

      ● 실무 예시

    • 학습 데이터 전처리: 여러 시험 점수를 'subject', 'score'로 녹여서 모델링

    • 시계열, 센서, 피처엔지니어링 등에서도 자주 사용


      2. pivot

      ● 목적

    • Long(세로) 데이터 → Wide(가로) 데이터로 변환

    • 한 행에 여러 값이 있을 때 각 컬럼으로 펼치기

      ● 기본 구조

      Before (long):

      idsubjectscore
      1math90
      2math70
      1eng80
      2eng60

      After (wide):

      idmatheng
      19080
      27060

      ● 사용법

      pivoted = melted.pivot(index='id', columns='subject', values='score')
      print(pivoted)
    • index: 행 기준

    • columns: 펼칠 컬럼

    • values: 실제 값

      ● 주의

    • 중복되는 index/columns 조합 있으면 에러

    • 여러 값 → 집계 필요할 땐 pivot_table 사용

      ● 실무 예시

    • 엑셀 피벗과 유사: 요약 표, 사용자별 상품별 구매액, 날짜별 그룹 집계


      3. stack / unstack

      ● 목적

    • MultiIndex(계층형) 구조에서 인덱스/컬럼을 서로 변환

    • 데이터의 “행/열 방향 계층”을 바꿔가며 여러 형태로 분석

      ● stack

    • 컬럼 → 인덱스로 변환 (행 방향 아래로 “쌓음”)

    • 결과: Series 또는 MultiIndex DataFrame

      ● 예시

      df2 = pd.DataFrame({
          'A': [1, 2],
          'B': [3, 4]
      }, index=['x', 'y'])
      stacked = df2.stack()
      print(stacked)
      # x  A    1
      #    B    3
      # y  A    2
      #    B    4

      ● unstack

    • 인덱스 → 컬럼으로 변환 (열 방향으로 “펼침”)

    • 계층 인덱스가 있을 때 사용

      ● 예시

      # 위의 stacked를 다시 DataFrame으로 복구
      unstacked = stacked.unstack()
      print(unstacked)

      ● 실무 예시

    • groupby 등으로 MultiIndex 만들어진 결과를 wide/long 변환

    • 시계열(시간별/카테고리별) 집계 후 요약


      4. pivot_table

    • pivot의 확장 버전

    • 중복값이 있어도 자동으로 집계해줌(aggfunc=)

      df = pd.DataFrame({
          'id':[1,1,2,2],
          'subject':['math','eng','math','eng'],
          'score':[90,80,70,60]
      })
      pt = pd.pivot_table(df, index='id', columns='subject', values='score', aggfunc='mean', fill_value=0)
      print(pt)

      5. 실무 요약 & 꿀팁

      목적함수주요 상황/팁
      wide→longmelt여러 열을 하나의 열로, EDA/머신러닝/시각화용
      long→widepivot행의 일부 값을 컬럼으로, 엑셀 피벗표 느낌
      중복 값까지 widepivot_table피벗+집계 기능, 중복값 자동 처리
      계층 변환stack컬럼→행 (아래로 쌓음), Series/MultiIndex DF 반환
      계층 변환unstack행→컬럼 (옆으로 펼침), MultiIndex 구조 처리

      6. 대표 에러/주의

    • pivot에서 중복 key값 있으면 ValueError (→ pivot_table 써야 함)

    • melt는 반드시 id_vars로 고정 컬럼 명시해야 함


      결론

    • melt, pivot, stack, unstack은 데이터 모양을 바꾸는 “필수” 도구

    • 실무에서는 집계, 시각화, 피처엔지니어링, EDA 할 때 항상 등장!

    • “행과 열을 자유자재로 변형”하는 게 데이터 분석의 핵심


profile
기록용 블로그

0개의 댓글