UNION ALL과 비슷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() 차이| 비교 | ignore_index=True | reset_index() | set_index() |
|---|---|---|---|
| 어디서 씀? | sort_values(), concat(), drop_duplicates(), groupby().apply() 등 | DataFrame 메서드 | DataFrame 메서드 |
| 역할 | 기존 인덱스 버리고 0부터 새 인덱스 부여 | 현재 인덱스를 컬럼으로 복구하고 0부터 새 인덱스 부여 | 특정 컬럼을 인덱스로 설정 |
| 기존 인덱스 | 완전 삭제됨 | 컬럼으로 이동 (drop=True면 삭제) | 기존 인덱스는 대체됨 |
| 주요 옵션 | ignore_index=True | drop=True (컬럼 버릴지 말지) | drop=False (컬럼 남길지) |
| 주 용도 | 정렬/합치기 후 인덱스 새로 부여 | 다중 인덱스 풀기, 초기화 | 기준 잡고 정리 정렬할 때 |
ignore_index=True : → "너네 인덱스 다 버리고 0부터 새로 번호 매길게."reset_index() : → "현재 인덱스를 컬럼으로 꺼내서, 기본 인덱스(0,1,2...)로 초기화할게."set_index() : → "이 컬럼을 새 인덱스로 삼을게."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'pd.merge(left, right, left_on='key', right_on='id')
pd.merge(df1, df2, on=['A', 'B'])
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') | 겹치는 컬럼명에 접미어 붙이기 |
merge보다 간단하게 쓸 때df1 = df1.set_index('A')
df2 = df2.set_index('A')
joined = df1.join(df2, lsuffix='_1', rsuffix='_2')
df1 = pd.DataFrame({'A': [1, np.nan], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})
df1.combine_first(df2)
pivotdf = 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
# 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')
df1.update(df2)
# df2에 있는 값으로 df1의 값 일부를 바로 덮어씀
# 행 추가 (Deprecated, concat 사용 권장)
df1.append(df2, ignore_index=True)
# 최신 권장
pd.concat([df1, df2], ignore_index=True)
pd.merge_asof(left, right, on='시간', direction='nearest')
특정 컬럼(또는 컬럼들) 값에 따라 데이터프레임을 “그룹”으로 나눔
나눈 그룹별로 집계/연산/구조변환 가능
여러 집계함수를 한 번에 그룹별로 적용
컬럼별로 다른 집계도 가능
df.groupby('성별').agg({'점수':['mean','max'], '나이':'min'})
그룹별로 집계값을 “원본 데이터 크기”로 다시 펼쳐줌
파생컬럼(예: 그룹별 평균, 그룹별 총합 등)을 만들 때 아주 많이 씀
df['성별_평균'] = df.groupby('성별')['점수'].transform('mean')
df['성별_총합'] = df.groupby('성별')['점수'].transform('sum')
원본 데이터 행 개수 그대로, 각 행에 맞는 그룹의 값이 “매핑”되어 들어감
그룹별로 임의의(커스텀) 함수를 적용해서, 그룹별로 결과를 자유롭게 만들 수 있음
집계뿐만 아니라, 각 그룹의 구조/형태를 “자유자재”로 변환할 수 있음
def top2(grp):
return grp.nlargest(2, '점수')
df.groupby('학년').apply(top2)
→ 각 학년별로 점수 top2만 남김 (그룹별 복잡한 변형/가공 가능)
그룹별 통계/순위/파생변수 생성
그룹별 구조 변환, 여러 단계의 계층 구조를 다루기
groupby와 melt/pivot/stack/unstack을 조합해서 데이터 모양을 자유자재로 바꿈
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)
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 |
실무 집계/변형/피처엔지니어링의 90%가 groupby/agg/transform/apply에서 끝난다!
집계, 파생컬럼, 그룹별 비율/순위, 그룹 조건필터, 다중 인덱스 등 모두 이 조합으로 해결
groupby/agg/transform/apply는 EDA/분석/전처리/특성 엔지니어링/구조변환까지
| 기능 | 함수/메서드 | 대표 예시/설명 |
|---|---|---|
| 수직/수평 연결 | concat | pd.concat([df1, df2], axis=0/1) |
| SQL식 병합 | merge | pd.merge(df1, df2, on='col', how='inner') |
| 인덱스 병합 | join | df1.join(df2, lsuffix, rsuffix) |
| 결측치 채움 | combine_first | df1.combine_first(df2) |
| 행/열 변환 | stack, unstack | df.stack(), df.unstack() |
| 와이드<->롱 | melt, pivot, pivot_table | pd.melt(), pd.pivot(), pd.pivot_table() |
| 값 덮어쓰기 | update | df1.update(df2) |
| 근사 병합 | merge_asof | pd.merge_asof(df1, df2, on='date') |
실전에서는 concat(단순합치기)와 merge(SQL JOIN)가 거의 필수!
데이터 구조를 자유자재로 바꾸려면 melt, pivot, stack/unstack 연습이 중요
combine_first로 결측치 보완, update로 특정 값만 덮어쓰기 등도 실전에서 자주 등장
melt, pivot, stack, unstack 정리
Wide(가로) 데이터 → Long(세로) 데이터로 변환
머신러닝, tidy data, 시각화, groupby 등에서 '길쭉한 형태' 필요할 때 사용
Before (wide):
| id | math | eng |
|---|---|---|
| 1 | 90 | 80 |
| 2 | 70 | 60 |
After (long):
| id | subject | score |
|---|---|---|
| 1 | math | 90 |
| 2 | math | 70 |
| 1 | eng | 80 |
| 2 | eng | 60 |
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'로 녹여서 모델링
시계열, 센서, 피처엔지니어링 등에서도 자주 사용
Long(세로) 데이터 → Wide(가로) 데이터로 변환
한 행에 여러 값이 있을 때 각 컬럼으로 펼치기
Before (long):
| id | subject | score |
|---|---|---|
| 1 | math | 90 |
| 2 | math | 70 |
| 1 | eng | 80 |
| 2 | eng | 60 |
After (wide):
| id | math | eng |
|---|---|---|
| 1 | 90 | 80 |
| 2 | 70 | 60 |
pivoted = melted.pivot(index='id', columns='subject', values='score')
print(pivoted)
index: 행 기준
columns: 펼칠 컬럼
values: 실제 값
중복되는 index/columns 조합 있으면 에러
여러 값 → 집계 필요할 땐 pivot_table 사용
엑셀 피벗과 유사: 요약 표, 사용자별 상품별 구매액, 날짜별 그룹 집계
MultiIndex(계층형) 구조에서 인덱스/컬럼을 서로 변환
데이터의 “행/열 방향 계층”을 바꿔가며 여러 형태로 분석
컬럼 → 인덱스로 변환 (행 방향 아래로 “쌓음”)
결과: 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
인덱스 → 컬럼으로 변환 (열 방향으로 “펼침”)
계층 인덱스가 있을 때 사용
# 위의 stacked를 다시 DataFrame으로 복구
unstacked = stacked.unstack()
print(unstacked)
groupby 등으로 MultiIndex 만들어진 결과를 wide/long 변환
시계열(시간별/카테고리별) 집계 후 요약
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)
| 목적 | 함수 | 주요 상황/팁 |
|---|---|---|
| wide→long | melt | 여러 열을 하나의 열로, EDA/머신러닝/시각화용 |
| long→wide | pivot | 행의 일부 값을 컬럼으로, 엑셀 피벗표 느낌 |
| 중복 값까지 wide | pivot_table | 피벗+집계 기능, 중복값 자동 처리 |
| 계층 변환 | stack | 컬럼→행 (아래로 쌓음), Series/MultiIndex DF 반환 |
| 계층 변환 | unstack | 행→컬럼 (옆으로 펼침), MultiIndex 구조 처리 |
pivot에서 중복 key값 있으면 ValueError (→ pivot_table 써야 함)
melt는 반드시 id_vars로 고정 컬럼 명시해야 함
melt, pivot, stack, unstack은 데이터 모양을 바꾸는 “필수” 도구
실무에서는 집계, 시각화, 피처엔지니어링, EDA 할 때 항상 등장!
“행과 열을 자유자재로 변형”하는 게 데이터 분석의 핵심