본문 바로가기
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 들의 서식지이기도 해. Row 수가 거의 확실히 잘못된 방향으로 바뀌어도 Pandas 는 경고 한 줄 안 하거든.

고전 함정 4가지

  1. 숨은 1-to-many fan-out. Right 테이블의 key 에 중복이 있으면 inner/left join 이 left row 를 부풀려. 1,000 row 였던 left 가 join 후 8,500 row 가 될 수 있어 — 그리고 매출이 세 배로 뛰고 나서야 알아채기도 해.
  2. Key 타입 불일치. String '42' 는 정수 42 와 안 만나. 한쪽 customer_idint64, 다른쪽은 string[pyarrow] — 현실에서 제일 자주 보는 꼴이야.
  3. 공백과 대소문자. 'NewYork''New York' 은 join 안 되고, 'NEW YORK''New York' 도 안 돼. Merge 전에 strip 하고 정규화해.
  4. Many-to-many 는 조용한 Cartesian. 같은 key 가 양쪽에 여러 번 있으면 row 가 곱으로 폭발해. Merge 전에 cardinality 를 검증해.

Pandas 는 정확히 이 cardinality 함정을 위해 mergevalidate= argument 를 마련해 놨어. 항상 써. 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

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

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