C.W.K.
Stream
Lesson 06 of 07 · published

테이블 Join — merge() 와 join key 함정

~13 min · pandas, merge, join, gotcha

Level 0구경꾼
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

SQL join, Pandas 방언

pd.merge(left, right, on='key', how='inner|left|right|outer') 는 SQL 에서 아는 네 가지 join 타입 + 보너스 하나 (cross) 구현. 테이블 결합의 일꾼 — 그리고 가장 임팩트 큰 silent bug 가 사는 곳이기도 해, 왜냐면 Pandas 가 거의 확실히 잘못된 방식으로 row 수 바뀌어도 경고 안 해.

고전 함정 4가지

  1. 묵시적 1-to-many fan-out. Right 테이블의 key 가 중복이면 inner/left join 이 left row 를 부풀려. 1,000 row left 가 join 후 8,500 row 가 될 수 있어 — 그리고 매출이 세 배 되기 전엔 못 알아챌 수 있어.
  2. Key 의 type mismatch. String '42' 를 정수 42 와 join 하면 매칭 안 돼. 한쪽엔 customer_idint64, 다른쪽엔 string[pyarrow] — 현실 고전.
  3. 공백 + case mismatch. 'NewYork''New York' 안 join. 'NEW YORK''New York' 안 join. Merge 전에 strip + 정규화.
  4. Many-to-many 가 silent Cartesian 으로. 양쪽에 같은 key 가 여러 번이면 곱으로 row 폭발. Merge 전에 cardinality 검증.

Pandas 는 정확히 cardinality 함정용 validate= argument 를 merge 에 노출. 항상 써. validate='one_to_one', 'one_to_many', 'many_to_one' 는 관계 안 맞으면 명시적 에러 raise — 원하는 거.

Code

방어적 merge — cardinality assert, row count 로깅·python
import pandas as pd

orders = pd.DataFrame({
    'order_id':    ['O1', 'O2', 'O3', 'O4'],
    'customer_id': ['C100', 'C100', 'C200', 'C300'],
    'amount_usd':  [100, 200, 50, 75],
})

customers = pd.DataFrame({
    'customer_id': ['C100', 'C200', 'C300'],
    'country':     ['KR',   'US',   'JP'],
    'tier':        ['gold', 'silver', 'bronze'],
})

# 방어적 merge — 명시적 how + cardinality validate
joined = orders.merge(
    customers,
    on='customer_id',
    how='left',
    validate='many_to_one',     # customers 에 customer_id 중복 있으면 raise
)

# Row count delta 항상 로깅 — 가장 싼 sanity check
assert len(joined) == len(orders), 'join 후 row count 가 예상과 다름'

# 방어적 정규화 — 양쪽 key strip + lower
# orders['customer_id']    = orders['customer_id'].str.strip()
# customers['customer_id'] = customers['customer_id'].str.strip()

External links

Exercise

orders 테이블과 customers 테이블 만드는데, customer dimension 에 실수로 중복 넣어. validate 없이 left merge 시도해서 row count 변화 관찰. 그리고 validate='many_to_one' 추가해서 Pandas raise 보기. Merged row count 와 left row count 비교 assertion 추가.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.