Pandas Merge: Python에서 DataFrame 병합하는 완벽 가이드
Updated on
현실 세계에서 단일 DataFrame으로 작업하는 것은 드뭅니다. 대부분의 데이터 분석 프로젝트는 여러 소스의 데이터를 결합해야 합니다 -- 판매 기록과 고객 프로필, 센서 측정값과 장치 메타데이터, 또는 설문 조사 응답과 인구 통계 테이블. pandas merge 함수는 Python 개발자가 DataFrame을 결합하는 데 사용하는 표준 도구이며, 이를 잘 이해하는 것이 데이터 준비에 몇 분 또는 몇 시간이 걸리는 차이입니다.
이 가이드는 pd.merge()의 모든 측면을 다룹니다: 네 가지 주요 조인 유형, 여러 열에서 병합, 중복 이름 처리 및 일반적인 함정. 모든 예제는 노트북에 직접 복사할 수 있는 작동 코드를 사용합니다.
pd.merge()의 기능
pd.merge()는 하나 이상의 공유 열(키라고 함)을 기반으로 행을 일치시켜 두 DataFrame을 결합합니다. SQL JOIN 문처럼 작동합니다. 일치시킬 열과 수행할 조인 유형을 선택하면 pandas가 나머지를 처리합니다.
기본 구문은 다음과 같습니다:
import pandas as pd
result = pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
suffixes=('_x', '_y'), indicator=False, validate=None)주요 매개변수 참조
| 매개변수 | 설명 | 기본값 |
|---|---|---|
left | 첫 번째(왼쪽) DataFrame | 필수 |
right | 두 번째(오른쪽) DataFrame | 필수 |
how | 조인 유형: 'inner', 'left', 'right', 'outer', 'cross' | 'inner' |
on | 조인할 열 이름(두 DataFrame에 모두 존재해야 함) | None |
left_on | 키로 사용할 왼쪽 DataFrame의 열 | None |
right_on | 키로 사용할 오른쪽 DataFrame의 열 | None |
left_index | 왼쪽 DataFrame의 인덱스를 조인 키로 사용 | False |
right_index | 오른쪽 DataFrame의 인덱스를 조인 키로 사용 | False |
suffixes | 겹치는 열 이름에 적용할 접미사 | ('_x', '_y') |
indicator | 각 행의 출처를 표시하는 열 추가 | False |
validate | 병합이 1대1, 1대다 등인지 확인 | None |
on, left_on, right_on을 생략하면 pandas는 두 DataFrame에서 동일한 이름을 공유하는 모든 열에서 자동으로 조인합니다.
모든 예제의 샘플 데이터
아래의 모든 예제는 이 두 DataFrame을 사용합니다:
import pandas as pd
employees = pd.DataFrame({
'emp_id': [1, 2, 3, 4, 5],
'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
'dept_id': [10, 20, 10, 30, 20]
})
departments = pd.DataFrame({
'dept_id': [10, 20, 40],
'dept_name': ['Engineering', 'Marketing', 'Sales']
})
print(employees)
print(departments)출력:
emp_id name dept_id
0 1 Alice 10
1 2 Bob 20
2 3 Charlie 10
3 4 Diana 30
4 5 Eve 20
dept_id dept_name
0 10 Engineering
1 20 Marketing
2 40 Salesdept_id 30은 employees에만 존재하고 dept_id 40은 departments에만 존재한다는 점에 유의하세요. 이러한 불일치는 의도적입니다 -- 조인 유형 간의 차이를 명확하게 만듭니다.
내부 조인(기본값)
내부 조인은 키가 두 DataFrame에 모두 존재하는 행만 반환합니다. 일치하지 않는 행은 삭제됩니다.
inner_result = pd.merge(employees, departments, on='dept_id', how='inner')
print(inner_result)출력:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 3 Charlie 10 Engineering
2 2 Bob 20 Marketing
3 5 Eve 20 MarketingDiana(dept_id=30)는 삭제됩니다. departments 테이블에 부서 30이 존재하지 않기 때문입니다. 부서 40(영업)도 없습니다. 그것에 속한 직원이 없기 때문입니다.
내부 조인을 사용하는 경우: 완전한 레코드만 원할 때 사용합니다 -- 양쪽에 유효한 데이터가 있는 행. 일치하지 않는 행에서 NaN 값을 도입하지 않기 때문에 가장 안전한 기본값입니다.
왼쪽 조인
왼쪽 조인은 왼쪽 DataFrame의 모든 행을 유지하고 오른쪽의 일치하는 행만 유지합니다. 일치하지 않는 곳에서는 오른쪽 열이 NaN으로 채워집니다.
left_result = pd.merge(employees, departments, on='dept_id', how='left')
print(left_result)출력:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 2 Bob 20 Marketing
2 3 Charlie 10 Engineering
3 4 Diana 30 NaN
4 5 Eve 20 MarketingDiana가 이제 포함되지만 그녀의 dept_name은 NaN입니다. departments 테이블에 부서 30의 항목이 없기 때문입니다.
왼쪽 조인을 사용하는 경우: 왼쪽 DataFrame이 "기본" 데이터셋이고 기본 테이블에서 행을 잃지 않고 추가 열로 보강하려는 경우 사용합니다. 이것이 실제로 가장 일반적인 병합 유형입니다.
오른쪽 조인
오른쪽 조인은 왼쪽 조인의 거울 이미지입니다. 오른쪽 DataFrame의 모든 행을 유지하고 왼쪽의 일치하는 행만 유지합니다.
right_result = pd.merge(employees, departments, on='dept_id', how='right')
print(right_result)출력:
emp_id name dept_id dept_name
0 1.0 Alice 10 Engineering
1 3.0 Charlie 10 Engineering
2 2.0 Bob 20 Marketing
3 5.0 Eve 20 Marketing
4 NaN NaN 40 Sales영업 부서(dept_id=40)가 이제 나타나지만 그것에 속한 직원이 없습니다. 해당 행의 직원 필드는 NaN입니다.
오른쪽 조인을 사용하는 경우: 실제로 오른쪽 조인은 드뭅니다. DataFrame 순서를 바꿔서 오른쪽 조인을 항상 왼쪽 조인으로 다시 작성할 수 있습니다. 대부분의 코드베이스는 일관성을 위해 왼쪽 조인을 선호합니다.
외부 조인(완전 외부 조인)
외부 조인은 두 DataFrame의 모든 행을 반환합니다. 일치하지 않는 곳에서는 누락된 값이 NaN으로 채워집니다.
outer_result = pd.merge(employees, departments, on='dept_id', how='outer')
print(outer_result)출력:
emp_id name dept_id dept_name
0 1.0 Alice 10 Engineering
1 3.0 Charlie 10 Engineering
2 2.0 Bob 20 Marketing
3 5.0 Eve 20 Marketing
4 4.0 Diana 30 NaN
5 NaN NaN 40 SalesDiana(일치하는 부서 없음)와 영업(일치하는 직원 없음) 모두 결과에 나타납니다.
외부 조인을 사용하는 경우: 두 데이터셋의 완전한 전체 그림이 필요하고 일치하지 않은 행을 식별하려는 경우 사용합니다. indicator 매개변수가 여기서 특히 유용합니다.
병합 유형 빠른 비교
| 병합 유형 | 왼쪽에서 유지 | 오른쪽에서 유지 | 일치하지 않는 행 |
|---|---|---|---|
inner | 일치만 | 일치만 | 삭제 |
left | 모든 행 | 일치만 | 왼쪽 행 유지, 오른쪽은 NaN으로 채움 |
right | 일치만 | 모든 행 | 오른쪽 행 유지, 왼쪽은 NaN으로 채움 |
outer | 모든 행 | 모든 행 | 양쪽 모두 유지, 일치 없는 곳은 NaN |
cross | 모든 행 | 모든 행 | 데카르트 곱(모든 조합) |
여러 열에서 병합
단일 열로는 일치를 고유하게 식별하기에 충분하지 않을 때 열 이름 목록을 on에 전달합니다:
sales = pd.DataFrame({
'year': [2024, 2024, 2025, 2025],
'quarter': ['Q1', 'Q2', 'Q1', 'Q2'],
'revenue': [100, 150, 200, 250]
})
targets = pd.DataFrame({
'year': [2024, 2024, 2025, 2025],
'quarter': ['Q1', 'Q2', 'Q1', 'Q2'],
'target': [120, 140, 210, 230]
})
merged = pd.merge(sales, targets, on=['year', 'quarter'])
print(merged)출력:
year quarter revenue target
0 2024 Q1 100 120
1 2024 Q2 150 140
2 2025 Q1 200 210
3 2025 Q2 250 230이것은 SQL의 복합 키와 동일합니다. 행을 조인하려면 year와 quarter 모두 일치해야 합니다.
다른 열 이름으로 병합
때때로 두 DataFrame이 동일한 개념에 대해 다른 이름을 사용합니다. on 대신 left_on과 right_on을 사용합니다:
orders = pd.DataFrame({
'order_id': [101, 102, 103],
'customer_id': [1, 2, 3],
'amount': [50.0, 75.0, 120.0]
})
customers = pd.DataFrame({
'id': [1, 2, 4],
'name': ['Alice', 'Bob', 'Diana']
})
merged = pd.merge(orders, customers, left_on='customer_id', right_on='id', how='left')
print(merged)출력:
order_id customer_id amount id name
0 101 1 50.0 1.0 Alice
1 102 2 75.0 2.0 Bob
2 103 3 120.0 NaN NaNcustomer_id와 id 열이 모두 결과에 나타나는 것에 유의하세요. 나중에 중복을 삭제할 수 있습니다:
merged = merged.drop(columns=['id'])접미사로 중복 열 이름 처리
두 DataFrame 모두 동일한 이름의 열이 있을 때(키 외에), pandas는 이들을 구별하기 위해 접미사를 추가합니다:
df1 = pd.DataFrame({
'id': [1, 2, 3],
'score': [85, 90, 78]
})
df2 = pd.DataFrame({
'id': [1, 2, 3],
'score': [88, 92, 80]
})
# 기본 접미사
merged = pd.merge(df1, df2, on='id')
print(merged)출력:
id score_x score_y
0 1 85 88
1 2 90 92
2 3 78 80열 이름을 더 의미 있게 만들기 위해 접미사를 사용자 정의할 수 있습니다:
merged = pd.merge(df1, df2, on='id', suffixes=('_midterm', '_final'))
print(merged)출력:
id score_midterm score_final
0 1 85 88
1 2 90 92
2 3 78 80Indicator 매개변수 사용
indicator 매개변수는 각 행이 어디서 왔는지 알려주는 _merge 열을 추가합니다:
result = pd.merge(employees, departments, on='dept_id', how='outer', indicator=True)
print(result)출력:
emp_id name dept_id dept_name _merge
0 1.0 Alice 10 Engineering both
1 3.0 Charlie 10 Engineering both
2 2.0 Bob 20 Marketing both
3 5.0 Eve 20 Marketing both
4 4.0 Diana 30 NaN left_only
5 NaN NaN 40 Sales right_only이것은 데이터 품질 검사에 매우 유용합니다 -- 일치하지 않은 행을 빠르게 필터링할 수 있습니다:
unmatched = result[result['_merge'] != 'both']
print(unmatched)merge()와 join()과 concat() -- 각각 사용하는 경우
Pandas는 DataFrame을 결합하는 세 가지 방법을 제공합니다. 각각 사용하는 경우는 다음과 같습니다:
| 기능 | pd.merge() | df.join() | pd.concat() |
|---|---|---|---|
| 조인 유형 | 열 기반(SQL과 유사) | 기본적으로 인덱스 기반 | 행 또는 열 스택 |
| 구문 | pd.merge(df1, df2, on='col') | df1.join(df2, on='col') | pd.concat([df1, df2]) |
| 최적 용도 | 공유 열에서 조인 | 인덱스에서 조인 | DataFrame을 수직/수평으로 스택 |
| 여러 키 | 예(on=['a','b']) | 제한적 | 해당 없음 |
| 여러 DataFrame | 한 번에 두 개 | 한 번에 두 개 | 한 번에 임의의 수 |
| 기본 조인 | 내부 조인 | 왼쪽 조인 | 외부 조인(axis=0) |
| 유연성 | 가장 높음 | 중간 | 다른 사용 사례 |
경험 법칙:
- 열 값을 기반으로 DataFrame을 결합할 때
pd.merge()를 사용합니다(가장 일반적인 경우). - 조인 키가 인덱스이고 더 짧은 구문을 원할 때
df.join()을 사용합니다. - DataFrame을 위아래로 쌓거나(행 추가) 나란히 배치할 때
pd.concat()을 사용합니다.
일반적인 오류 및 문제 해결
1. MergeError: 열이 겹치지만 접미사가 지정되지 않음
두 DataFrame 모두 동일한 이름의 비키 열이 있고 suffixes=(False, False)를 설정한 경우 발생합니다:
# 수정: 의미 있는 접미사 사용
merged = pd.merge(df1, df2, on='id', suffixes=('_left', '_right'))2. 예상치 못한 행 폭발(다대다 병합)
두 DataFrame 모두 조인 키에 중복 값이 있는 경우 pandas는 일치하는 행의 데카르트 곱을 생성합니다. 이로 인해 결과의 행 수가 입력보다 훨씬 많을 수 있습니다:
# 병합 전에 중복 확인
print(df1['key'].duplicated().sum())
print(df2['key'].duplicated().sum())
# validate를 사용하여 조기에 포착
merged = pd.merge(df1, df2, on='key', validate='one_to_many')validate 매개변수는 'one_to_one', 'one_to_many', 'many_to_one', 'many_to_many'를 허용합니다. 데이터가 예상 카디널리티와 일치하지 않으면 MergeError를 발생시킵니다.
3. 키 열의 데이터 타입이 다름
하나의 DataFrame이 키를 int64로 저장하고 다른 하나는 object(문자열)로 저장하는 경우 병합이 실패하거나 0 일치를 생성합니다:
# 데이터 타입 확인
print(df1['id'].dtype) # int64
print(df2['id'].dtype) # object
# 수정: 동일한 타입으로 캐스트
df2['id'] = df2['id'].astype(int)
merged = pd.merge(df1, df2, on='id')4. 키의 NaN 값
조인 키 열에 NaN이 있는 행은 아무것도 일치하지 않습니다(pandas에서 NaN != NaN). 먼저 삭제하거나 채웁니다:
df1 = df1.dropna(subset=['key'])PyGWalker로 병합된 DataFrame 시각화
데이터를 병합한 후 다음 단계는 일반적으로 결과를 탐색하는 것입니다 -- 분포를 보고, 패턴을 찾고, 이상값을 확인합니다. 수십 개의 matplotlib 또는 seaborn 호출을 작성하는 대신 PyGWalker (opens in a new tab)를 사용할 수 있습니다. 이는 Jupyter Notebook 내에서 직접 모든 pandas DataFrame을 대화형 Tableau와 유사한 시각적 탐색 인터페이스로 변환하는 오픈 소스 Python 라이브러리입니다.
import pandas as pd
import pygwalker as pyg
# DataFrame 병합
employees = pd.DataFrame({
'emp_id': [1, 2, 3, 4, 5],
'name': ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve'],
'dept_id': [10, 20, 10, 30, 20],
'salary': [95000, 82000, 105000, 78000, 91000]
})
departments = pd.DataFrame({
'dept_id': [10, 20, 30],
'dept_name': ['Engineering', 'Marketing', 'Design']
})
merged = pd.merge(employees, departments, on='dept_id')
# 대화형 시각화 시작 -- 드래그 앤 드롭으로 탐색
walker = pyg.walk(merged)PyGWalker를 사용하면 dept_name을 x축으로, salary를 y축으로 드래그하여 부서별 급여 분포를 즉시 확인할 수 있습니다 -- 차트 코드가 필요 없습니다. 필드를 드래그하는 것만으로 막대 차트, 산점도, 히스토그램 등을 만들 수 있습니다. 조인이 예상대로 작동했는지 확인해야 하는 복잡한 병합 결과를 탐색하는 데 특히 강력합니다.
Google Colab (opens in a new tab), Kaggle (opens in a new tab)에서 지금 바로 PyGWalker를 사용해 보거나
pip install pygwalker로 설치할 수 있습니다.
FAQ
pandas merge와 join의 차이점은 무엇인가요?
pd.merge()는 기본적으로 열 값을 기반으로 DataFrame을 조인하고 모든 조인 유형(내부, 왼쪽, 오른쪽, 외부, 교차)을 지원합니다. df.join()은 기본적으로 인덱스에서 조인하고 왼쪽 조인을 사용합니다. 내부적으로 join()은 merge()를 호출하므로 동일한 결과를 생성합니다 -- merge()는 단순히 일치할 열에 대한 더 많은 제어를 제공합니다.
pandas에서 여러 열로 두 DataFrame을 병합하려면 어떻게 해야 하나요?
열 이름 목록을 on 매개변수에 전달합니다: pd.merge(df1, df2, on=['col_a', 'col_b']). 행을 조인하려면 두 열이 모두 일치해야 합니다. 이것은 SQL의 복합 키와 동일합니다.
왜 내 pandas merge가 중복 행을 만드나요?
조인 키가 하나 또는 두 DataFrame에서 반복된 값을 가질 때 중복 행이 나타납니다. Pandas는 일치하는 모든 행의 데카르트 곱을 생성합니다. 병합 전에 df.duplicated(subset=['key']).sum()을 사용하여 중복을 확인하거나 validate='one_to_one'을 사용하여 조기에 포착합니다.
pandas의 교차 병합이란 무엇인가요?
교차 병합(how='cross')은 두 DataFrame의 데카르트 곱을 생성합니다 -- 왼쪽의 모든 행이 오른쪽의 모든 행과 쌍을 이룹니다. 왼쪽에 3개 행이 있고 오른쪽에 4개 행이 있으면 결과는 12개 행이 됩니다. 모든 제품을 모든 매장 위치와 쌍을 이루는 것과 같이 가능한 모든 조합을 생성하는 데 유용합니다.
인덱스에서 pandas merge를 수행하려면 어떻게 해야 하나요?
left_index=True 및/또는 right_index=True를 설정합니다: pd.merge(df1, df2, left_index=True, right_index=True). 인덱스와 열 키를 혼합할 수도 있습니다: pd.merge(df1, df2, left_on='col_a', right_index=True).
결론
pandas merge() 함수는 Python에서 DataFrame을 결합하는 가장 유연하고 널리 사용되는 도구입니다. 주요 포인트를 요약하면:
- 내부 조인(기본값)은 두 DataFrame에서 모두 일치하는 행만 유지합니다.
- 왼쪽 조인은 왼쪽 DataFrame의 모든 행을 유지하고 오른쪽에 일치하지 않는 곳에 NaN을 채웁니다.
- 오른쪽 조인은 오른쪽 DataFrame의 모든 행을 유지합니다 -- 그러나 일관성을 위해 순서를 바꾼 왼쪽 조인을 선호합니다.
- 외부 조인은 양쪽의 모든 것을 유지하며,
indicator=True로 일치하지 않는 레코드를 식별하는 데 유용합니다. - 동일한 이름 키에는
on을 사용하고, 다른 이름 키에는left_on/right_on을 사용하고, 겹치는 열을 처리하려면suffixes를 사용합니다. - 예상치 못한 결과를 피하기 위해 병합 전에 항상 중복 키와 일치하지 않는 데이터 타입을 확인합니다.
데이터가 병합되면 PyGWalker (opens in a new tab)와 같은 도구를 사용하면 차트 코드를 작성하지 않고도 결과를 시각적으로 탐색할 수 있어 전체 분석 워크플로우가 더 빠르고 직관적입니다.