Menu

R에서 데이터 프레임 병합과 조인 (merge, left_join)

공통 키로 데이터 프레임 결합하기: 내부·왼쪽·오른쪽·완전 조인을 위한 merge(), by.x/by.y로 서로 다른 키 이름 다루기, dplyr의 조인 계열, 그리고 행을 쌓는 rbind().

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

두 개의 표, 하나의 키

실제 데이터가 표 하나에만 담기는 경우는 드뭅니다. 고객은 한 데이터 프레임에, 주문은 다른 데이터 프레임에 들어 있고, "고객마다 얼마를 썼는가?"라는 질문에는 둘 다 필요합니다. 이들을 연결하는 것이 입니다: 각 표에 존재하며 같은 개체를 식별하는 열이죠. 키로 표를 결합하는 것을 조인(SQL의 용어) 또는 병합(base R의 용어)이라고 합니다. 같은 연산입니다.

이 페이지의 나머지 부분에서 사용할 표 한 쌍입니다. 고객 5번은 주문을 했지만 고객 표에는 없고, 고객 2번과 4번은 한 번도 주문하지 않았다는 점을 눈여겨보세요:

불일치는 의도한 것입니다 - 조인이 매칭되지 않은 행을 어떻게 처리하느냐가 바로 조인 종류를 가르는 기준이기 때문입니다.

merge(): 기본은 내부 조인

merge(x, y, by = "key")는 키가 같은 행을 매칭해 열을 이어 붙입니다. 기본적으로 양쪽 표에 모두 존재하는 키만 남깁니다 - 내부 조인입니다:

세 행이 돌아옵니다. Ana는 두 번 나타납니다 - 주문이 두 건이고, 조인은 매칭되는 마다 출력 행을 하나씩 만듭니다. Ben과 Dana는 사라졌고(주문 없음), 고객 5번의 정체불명 주문도 사라졌습니다(고객 없음). 내부 조인은 양쪽 표에서 매칭되지 않은 행을 조용히 버립니다 - 완전한 쌍만 중요할 때는 정확히 옳고, 그렇지 않을 때는 조용한 데이터 손실 버그입니다.

왼쪽, 오른쪽, 완전 조인: all.x, all.y, all

매칭되지 않은 행을 유지하려면 어느 표의 행이 신성불가침인지 지정하세요. all.x = TRUE는 첫 번째 표의 모든 행을 유지합니다 - 왼쪽 조인 이며 실무에서 가장 많이 쓰입니다:

이제 Ben과 Dana가 amountNA를 달고 살아남습니다 - "이 고객은 존재하지만 매칭되는 주문이 없다"는 뜻이죠. 이 NA들은 쓰레기가 아니라 정보입니다: is.na(result$amount)가 곧 한 번도 주문하지 않은 고객 목록입니다(결측값 문서에서 다루는 법을 설명합니다). 나머지 변형은 같은 아이디어를 다른 쪽으로 향하게 한 것입니다: all.y = TRUE는 두 번째 표의 모든 행을 유지하고(오른쪽 조인 - 정체불명 고객 5번의 주문이 nameNA를 달고 살아남습니다), all = TRUE는 양쪽 모두를 유지합니다(완전 조인).

이렇게 자문하며 고르세요: 어느 쪽 행을 잃어서는 안 되는가? 마스터 표를 참조 데이터로 보강한다면 - 왼쪽 조인, 마스터 표를 먼저. 양방향을 감사한다면 - 완전 조인입니다.

서로 다른 키 이름: by.x와 by.y

표들이 이름 규칙에서 일치하는 경우는 드뭅니다 - 한쪽은 id, 다른 쪽은 customer_id이죠. 이름을 바꾸지 말고 merge()에 두 이름을 알려 주세요:

출력은 키에 대해 첫 번째 표의 이름을 유지합니다. 관련해서, 두 표가 키가 아닌 열 이름을 공유하면(둘 다 date가 있는 경우 등) merge는 date.xdate.y처럼 접미사를 붙입니다 - 읽기 나쁘니 바로 이름을 바꾸세요.

dplyr의 조인들

dplyr은 조인 종류마다 전용 동사를 제공하므로, 의도가 플래그 인자가 아니라 함수 이름에 드러납니다(정적 예제입니다. 샌드박스는 base R만 실행합니다):

library(dplyr)

left_join(customers, orders, by = "id")
inner_join(customers, orders, by = "id")
full_join(customers, orders, by = "id")
left_join(customers, orders, by = c("id" = "customer_id"))  # different names

가독성 외에도 left_join()은 첫 번째 표의 행 순서를 보존하고(merge()는 키로 재정렬합니다) 다대다 매칭에 대해 큰 소리로 경고합니다 - 동사 가족은 dplyr 입문을 참고하세요.

과소평가된 멤버는 anti_join() 입니다: 두 번째 표에 매칭이 없는 첫 번째 표의 행을 반환합니다 - 열은 추가하지 않고 남은 행만 줍니다:

anti_join(customers, orders, by = "id")   # customers who never ordered

"어떤 행이 매칭에 실패했는가?"라는 질문은 데이터 정제에서 끊임없이 등장하며(매칭 안 된 ID, 고아 레코드, 실패한 조회), base R에서는 customers[!(customers$id %in% orders$id), ]가 필요한 일을 anti_join()은 한 번의 호출로 해냅니다.

행 쌓기: rbind()

조인은 두 표의 을 결합합니다. 대신 같은 종류 의 행 묶음이 둘 있다면 - 1월 주문과 2월 주문처럼 - rbind()로 쌓습니다:

요구 조건은 엄격합니다: 두 데이터 프레임의 열 이름이 같아야 합니다(순서는 상관없습니다 - rbind는 이름으로 매칭합니다). 열이 빠지거나 더 있으면 NA로 채워지는 게 아니라 오류가 납니다. 묶음마다 열 구성이 어긋났다면 dplyr의 bind_rows()가 더 관대합니다 - 이름으로 정렬하고 빈 자리를 NA로 채웁니다.

중복 키 폭발

전형적인 조인 사고: 고유하다고 믿었던 키가 양쪽 표 모두에서 고유하지 않은 경우입니다. 매칭마다 서로 짝지어지며 행이 배로 늘어납니다:

두 행과 두 행을 조인하면 행이 나옵니다 - 각 x가 각 y와 짝지어지죠. 실제 데이터에서는 이런 식으로 1만 행짜리 표가 300만 행이 되고 매출 합계가 두 배가 됩니다. merge()는 이 일을 조용히 합니다. 방어책은 습관입니다: 조인 전에 고유하다고 가정한 키를 확인하고(anyDuplicated(customers$id)0이어야 합니다), 조인 후에는 nrow()가 예상과 맞는지 점검하세요.

핵심 정리

  • merge(x, y, by = "key")는 내부 조인이며, 매칭되지 않은 행은 조용히 사라집니다.
  • all.x = TRUE(왼쪽), all.y = TRUE(오른쪽), all = TRUE(완전)는 매칭되지 않은 행을 NA로 채워 유지합니다.
  • 키 이름이 다르면 base R에서는 by.x / by.y, dplyr에서는 by = c("a" = "b")를 씁니다.
  • dplyr은 조인마다 이름을 붙입니다. 매칭에 실패한 행을 주는 anti_join()이 과소평가된 도구입니다.
  • rbind()는 형태가 같은 표를 쌓습니다. 열은 이름으로 일치해야 합니다.
  • 중복 키는 조용히 행을 늘립니다 - 앞에서는 anyDuplicated(), 뒤에서는 nrow()를 확인하세요.

다음 주제: pivot_longer()pivot_wider()로 넓은 형식과 긴 형식 사이를 오가며 재구조화하기.

자주 묻는 질문

R에서 두 데이터 프레임을 어떻게 병합하나요?

공통 키 열과 함께 merge(x, y, by = "key")를 사용합니다. 기본값은 내부 조인이라서 키가 양쪽 데이터 프레임 모두에 있는 행만 남습니다. 왼쪽 조인은 all.x = TRUE, 오른쪽 조인은 all.y = TRUE, 완전 조인은 all = TRUE를 추가하세요.

R에서 왼쪽 조인은 어떻게 하나요?

base R: merge(x, y, by = "key", all.x = TRUE)는 x의 모든 행을 유지하고 매칭되는 값이 없는 y 열은 NA로 채웁니다. dplyr: left_join(x, y, by = "key") - 결과는 같지만 x의 원래 행 순서까지 보존합니다. merge()는 그렇지 않습니다.

키 열의 이름이 서로 다를 때 데이터 프레임을 어떻게 병합하나요?

merge()에 두 이름을 모두 알려 줍니다: merge(x, y, by.x = "id", by.y = "customer_id"). dplyr에서 대응되는 표현은 left_join(x, y, by = c("id" = "customer_id"))이고, 최신 헬퍼를 쓰면 by = join_by(id == customer_id)입니다.

R에서 merge와 rbind의 차이는 무엇인가요?

결합하는 방향이 다릅니다. merge()는 두 표의 행을 키로 매칭해 열을 합칩니다 - 조인이죠. rbind()는 한 표의 행을 다른 표 아래에 쌓으며, 두 표의 열 이름이 같아야 합니다. 열이 동일한 월별 파일에는 rbind()가, 고객과 주문 결합에는 merge()가 필요합니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기