[r] 데이터 프레임 결합 (병합) 방법 (내부, 외부, 왼쪽, 오른쪽)

두 개의 데이터 프레임이 주어지면 :

df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2, 4, 6), State = c(rep("Alabama", 2), rep("Ohio", 1)))

df1
#  CustomerId Product
#           1 Toaster
#           2 Toaster
#           3 Toaster
#           4   Radio
#           5   Radio
#           6   Radio

df2
#  CustomerId   State
#           2 Alabama
#           4 Alabama
#           6    Ohio

데이터베이스 스타일, 즉 SQL 스타일을 조인하려면 어떻게해야합니까? 즉, 어떻게 얻을 수 있습니까?

  • 내부 조인df1df2:
    왼쪽 테이블에 오른쪽 테이블에 키를 일치 한있는 돌아 행만.
  • 외부 조인df1df2:
    두 테이블에서 반환 모든 행은 오른쪽 테이블에 일치하는 키가 왼쪽에서 레코드를 가입 할 수 있습니다.
  • A는 외부 조인 (또는 간단히 왼쪽에 가입) 왼쪽df1df2
    우측 테이블에서 키를 일치하는 반환 왼쪽 테이블의 모든 행과 행을.
  • 오른쪽 외부 조인df1df2
    왼쪽 테이블에서 키를 일치하는 오른쪽 테이블의 모든 행과 행을 반환.

추가 크레딧 :

SQL 스타일 select 문을 어떻게 수행 할 수 있습니까?



답변

merge기능 및 선택적 매개 변수 를 사용하여 다음을 수행하십시오.

내부 조인 : merge(df1, df2) R은 공통 변수 이름으로 프레임을 자동으로 조인하기 때문에 이러한 예제에서 작동하지만merge(df1, df2, by = "CustomerId")원하는 필드에서만 일치하도록 지정하려고합니다. 일치하는 변수의 이름이 다른 데이터 프레임에서 다른 경우by.xby.y매개 변수를사용할 수도 있습니다.

외부 조인 : merge(x = df1, y = df2, by = "CustomerId", all = TRUE)

왼쪽 바깥 쪽 : merge(x = df1, y = df2, by = "CustomerId", all.x = TRUE)

오른쪽 바깥 쪽 : merge(x = df1, y = df2, by = "CustomerId", all.y = TRUE)

크로스 조인 : merge(x = df1, y = df2, by = NULL)

내부 조인과 마찬가지로 일치 변수로 “CustomerId”를 R에 명시 적으로 전달할 수 있습니다. 거의 항상 병합하려는 식별자를 명시 적으로 언급하는 것이 가장 좋습니다. 입력 데이터 프레임이 예기치 않게 변경되고 나중에 읽기가 더 안전합니다.

by벡터 를 제공 하여 여러 열을 병합 할 수 있습니다 ( 예 🙂 by = c("CustomerId", "OrderId").

병합에 열 이름에 동일하지 않으면, 당신은, 예를 들어, 지정할 수 있습니다 by.x = "CustomerId_in_df1", by.y = "CustomerId_in_df2"경우 CustomerId_in_df1첫 번째 데이터 프레임의 열 이름이고, CustomerId_in_df2두 번째 데이터 프레임의 열 이름입니다. 여러 열에서 병합해야하는 경우 벡터가 될 수도 있습니다.


답변

Gabor Grothendieck의 sqldf package를 확인하여 이러한 작업을 SQL로 표현할 수 있습니다.

library(sqldf)

## inner join
df3 <- sqldf("SELECT CustomerId, Product, State
              FROM df1
              JOIN df2 USING(CustomerID)")

## left join (substitute 'right' for right join)
df4 <- sqldf("SELECT CustomerId, Product, State
              FROM df1
              LEFT JOIN df2 USING(CustomerID)")

SQL 구문이 R과 동등한 것보다 간단하고 자연 스럽다는 것을 알았습니다 (그러나 이것은 내 RDBMS 편향을 반영 할 수 있습니다).

조인에 대한 자세한 내용 은 Gabor의 sqldf GitHub 를 참조하십시오.


답변

내부 조인 에는 data.table 접근 방식이 있으며 시간과 메모리 효율성이 뛰어나며 더 큰 데이터 프레임에 필요합니다.

library(data.table)

dt1 <- data.table(df1, key = "CustomerId")
dt2 <- data.table(df2, key = "CustomerId")

joined.dt1.dt.2 <- dt1[dt2]

mergedata.tables에서도 작동합니다 (일반적이고 호출하기 때문에 merge.data.table)

merge(dt1, dt2)

stackoverflow에 문서화 된 data.table :
data.table 병합 작업을 수행하는 방법
외래 키의 SQL 조인을 R data.table 구문으로 변환 중대형 데이터
를 병합하는 효율적인 대안 프레임 R 데이터
와 기본 왼쪽 외부 조인을 수행하는 방법 R에?

또 다른 옵션은 plyr 패키지 join에있는 기능입니다

library(plyr)

join(df1, df2,
     type = "inner")

#   CustomerId Product   State
# 1          2 Toaster Alabama
# 2          4   Radio Alabama
# 3          6   Radio    Ohio

옵션 type: inner, left, right, full.

From ?join:와 달리 merge[ join]는 어떤 조인 유형이 사용 되더라도 x 순서를 유지합니다.


답변

Hadley Wickham의 멋진 dplyr 패키지를 사용하여 조인을 수행 할 수도 있습니다 .

library(dplyr)

#make sure that CustomerId cols are both type numeric
#they ARE not using the provided code in question and dplyr will complain
df1$CustomerId <- as.numeric(df1$CustomerId)
df2$CustomerId <- as.numeric(df2$CustomerId)

조인 변경 : df2의 일치 항목을 사용하여 df1에 열 추가

#inner
inner_join(df1, df2)

#left outer
left_join(df1, df2)

#right outer
right_join(df1, df2)

#alternate right outer
left_join(df2, df1)

#full join
full_join(df1, df2)

필터링 조인 : df1에서 행을 필터링하고 열을 수정하지 마십시오.

semi_join(df1, df2) #keep only observations in df1 that match in df2.
anti_join(df1, df2) #drops all observations in df1 that match in df2.


답변

R Wiki 에서이 작업을 수행하는 좋은 예가 있습니다. 나는 여기서 몇 가지를 훔칠 것이다 :

병합 방법

키 이름이 동일하기 때문에 내부 조인을 수행하는 짧은 방법은 merge ()입니다.

merge(df1,df2)

“all”키워드를 사용하여 전체 내부 조인 (두 테이블의 모든 레코드)을 작성할 수 있습니다.

merge(df1,df2, all=TRUE)

df1 및 df2의 왼쪽 외부 조인 :

merge(df1,df2, all.x=TRUE)

df1과 df2의 오른쪽 외부 조인 :

merge(df1,df2, all.y=TRUE)

당신은 그것을 뒤집고, 때리고 그들을 문지르면 다른 두 개의 외부 조인을 얻을 수 있습니다 🙂

첨자 방법

아래 첨자 방법을 사용하여 왼쪽에서 df1을 사용하는 왼쪽 외부 조인은 다음과 같습니다.

df1[,"State"]<-df2[df1[ ,"Product"], "State"]

외부 외부 조인의 다른 조합은 왼쪽 외부 조인 첨자 예제를 병합하여 만들 수 있습니다. (그렇습니다. “독자 운동으로 남겨 두겠습니다 …”라고 말하는 것과 같습니다.


답변

2014 년 새로운 기능 :

특히 정렬, 필터링, 하위 설정, 요약 등의 일반적인 데이터 조작에 관심 dplyr이있는 경우 데이터 프레임을 사용하여 작업을 용이하게하도록 설계된 다양한 기능이 포함 된을 살펴보십시오. 그리고 다른 특정 데이터베이스 유형. 심지어 매우 정교한 SQL 인터페이스와 (대부분의) SQL 코드를 R로 직접 변환하는 기능도 제공합니다.

dplyr 패키지의 4 가지 조인 관련 함수는 다음과 같습니다.

  • inner_join(x, y, by = NULL, copy = FALSE, ...): y에 일치하는 값이있는 x의 모든 행과 x와 y의 모든 열을 반환합니다.
  • left_join(x, y, by = NULL, copy = FALSE, ...): x의 모든 행과 x와 y의 모든 열을 반환합니다.
  • semi_join(x, y, by = NULL, copy = FALSE, ...): x의 열만 유지하면서 y에 일치하는 값이있는 x의 모든 행을 반환합니다.
  • anti_join(x, y, by = NULL, copy = FALSE, ...): x의 열만 유지하면서 y에 일치하는 값이없는 x의 모든 행을 반환합니다.

여기 에 모두 자세히 설명되어 있습니다.

로 열을 선택할 수 있습니다 select(df,"column"). 그것이 SQL-ish가 충분하지 않으면 SQL sql()코드를 그대로 입력 할 수 있는 기능이 있으며 R을 모두 쓰는 것처럼 지정한 작업을 수행합니다 (자세한 내용은 참조하십시오. 받는 사람 dplyr / 데이터베이스 비네팅 ). 예를 들어, 올바르게 적용되면 sql("SELECT * FROM hflights")“hflights”dplyr 테이블 ( “tbl”)에서 모든 열을 선택합니다.


답변

데이터 세트 가입을위한 data.table 메서드 업데이트 각 조인 유형에 대한 아래 예를 참조하십시오. 두 [.data.table번째 data.table을 하위 집합에 대한 첫 번째 인수로 전달할 때 부터 두 가지 방법이 있으며 , 다른 방법은 merge빠른 data.table 메서드에 디스패치 하는 함수 를 사용 하는 것입니다.

df1 = data.frame(CustomerId = c(1:6), Product = c(rep("Toaster", 3), rep("Radio", 3)))
df2 = data.frame(CustomerId = c(2L, 4L, 7L), State = c(rep("Alabama", 2), rep("Ohio", 1))) # one value changed to show full outer join

library(data.table)

dt1 = as.data.table(df1)
dt2 = as.data.table(df2)
setkey(dt1, CustomerId)
setkey(dt2, CustomerId)
# right outer join keyed data.tables
dt1[dt2]

setkey(dt1, NULL)
setkey(dt2, NULL)
# right outer join unkeyed data.tables - use `on` argument
dt1[dt2, on = "CustomerId"]

# left outer join - swap dt1 with dt2
dt2[dt1, on = "CustomerId"]

# inner join - use `nomatch` argument
dt1[dt2, nomatch=NULL, on = "CustomerId"]

# anti join - use `!` operator
dt1[!dt2, on = "CustomerId"]

# inner join - using merge method
merge(dt1, dt2, by = "CustomerId")

# full outer join
merge(dt1, dt2, by = "CustomerId", all = TRUE)

# see ?merge.data.table arguments for other cases

아래의 벤치 마크는 기본 R, sqldf, dplyr 및 data.table을 테스트합니다.
벤치 마크는 키가없는 / 인덱싱되지 않은 데이터 세트를 테스트합니다. 벤치 마크는 50M-1 행 데이터 세트에서 수행되며, 조인 열에는 50M-2 공통 값이 있으므로 각 시나리오 (내부, 왼쪽, 오른쪽, 전체)를 테스트 할 수 있으며 조인은 여전히 ​​쉽지 않습니다. 결합 알고리즘을 잘 강조하는 결합 유형입니다. 타이밍이의 같다 sqldf:0.4.11, dplyr:0.7.8, data.table:1.12.0.

# inner
Unit: seconds
   expr       min        lq      mean    median        uq       max neval
   base 111.66266 111.66266 111.66266 111.66266 111.66266 111.66266     1
  sqldf 624.88388 624.88388 624.88388 624.88388 624.88388 624.88388     1
  dplyr  51.91233  51.91233  51.91233  51.91233  51.91233  51.91233     1
     DT  10.40552  10.40552  10.40552  10.40552  10.40552  10.40552     1
# left
Unit: seconds
   expr        min         lq       mean     median         uq        max
   base 142.782030 142.782030 142.782030 142.782030 142.782030 142.782030
  sqldf 613.917109 613.917109 613.917109 613.917109 613.917109 613.917109
  dplyr  49.711912  49.711912  49.711912  49.711912  49.711912  49.711912
     DT   9.674348   9.674348   9.674348   9.674348   9.674348   9.674348
# right
Unit: seconds
   expr        min         lq       mean     median         uq        max
   base 122.366301 122.366301 122.366301 122.366301 122.366301 122.366301
  sqldf 611.119157 611.119157 611.119157 611.119157 611.119157 611.119157
  dplyr  50.384841  50.384841  50.384841  50.384841  50.384841  50.384841
     DT   9.899145   9.899145   9.899145   9.899145   9.899145   9.899145
# full
Unit: seconds
  expr       min        lq      mean    median        uq       max neval
  base 141.79464 141.79464 141.79464 141.79464 141.79464 141.79464     1
 dplyr  94.66436  94.66436  94.66436  94.66436  94.66436  94.66436     1
    DT  21.62573  21.62573  21.62573  21.62573  21.62573  21.62573     1

당신이 사용하여 수행 할 수있는 조인의 다른 종류가 있습니다주의 data.table:
가입에 대한 업데이트를 당신이 당신의 기본 테이블에 다른 테이블의 값을 조회하려면 –
가입에 집계 당신은 당신이하지 않아도 합류 키를 집계 할 경우 – 모든 결과에 가입 실현하기
가입 중복 당신이 범위에 의해 병합 할 경우 –
압연 가입 – 당신이 병합 / 선행 전방 또는 후방을 굴려 행을 다음의 값에 일치 할 수 있도록하려면
비 동등 가입 – 경우 조인 조건이 동일하지 않습니다

재현 할 코드 :

library(microbenchmark)
library(sqldf)
library(dplyr)
library(data.table)
sapply(c("sqldf","dplyr","data.table"), packageVersion, simplify=FALSE)

n = 5e7
set.seed(108)
df1 = data.frame(x=sample(n,n-1L), y1=rnorm(n-1L))
df2 = data.frame(x=sample(n,n-1L), y2=rnorm(n-1L))
dt1 = as.data.table(df1)
dt2 = as.data.table(df2)

mb = list()
# inner join
microbenchmark(times = 1L,
               base = merge(df1, df2, by = "x"),
               sqldf = sqldf("SELECT * FROM df1 INNER JOIN df2 ON df1.x = df2.x"),
               dplyr = inner_join(df1, df2, by = "x"),
               DT = dt1[dt2, nomatch=NULL, on = "x"]) -> mb$inner

# left outer join
microbenchmark(times = 1L,
               base = merge(df1, df2, by = "x", all.x = TRUE),
               sqldf = sqldf("SELECT * FROM df1 LEFT OUTER JOIN df2 ON df1.x = df2.x"),
               dplyr = left_join(df1, df2, by = c("x"="x")),
               DT = dt2[dt1, on = "x"]) -> mb$left

# right outer join
microbenchmark(times = 1L,
               base = merge(df1, df2, by = "x", all.y = TRUE),
               sqldf = sqldf("SELECT * FROM df2 LEFT OUTER JOIN df1 ON df2.x = df1.x"),
               dplyr = right_join(df1, df2, by = "x"),
               DT = dt1[dt2, on = "x"]) -> mb$right

# full outer join
microbenchmark(times = 1L,
               base = merge(df1, df2, by = "x", all = TRUE),
               dplyr = full_join(df1, df2, by = "x"),
               DT = merge(dt1, dt2, by = "x", all = TRUE)) -> mb$full

lapply(mb, print) -> nul