Skip to content
주제
Pandas
Pandas Merge: The Complete Guide to Merging DataFrames in Python

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        Sales

dept_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    Marketing

Diana(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    Marketing

Diana가 이제 포함되지만 그녀의 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        Sales

Diana(일치하는 부서 없음)와 영업(일치하는 직원 없음) 모두 결과에 나타납니다.

외부 조인을 사용하는 경우: 두 데이터셋의 완전한 전체 그림이 필요하고 일치하지 않은 행을 식별하려는 경우 사용합니다. 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의 복합 키와 동일합니다. 행을 조인하려면 yearquarter 모두 일치해야 합니다.

다른 열 이름으로 병합

때때로 두 DataFrame이 동일한 개념에 대해 다른 이름을 사용합니다. on 대신 left_onright_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    NaN

customer_idid 열이 모두 결과에 나타나는 것에 유의하세요. 나중에 중복을 삭제할 수 있습니다:

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           80

Indicator 매개변수 사용

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)와 같은 도구를 사용하면 차트 코드를 작성하지 않고도 결과를 시각적으로 탐색할 수 있어 전체 분석 워크플로우가 더 빠르고 직관적입니다.

📚