병합하려는 많은 data.frames 목록이 있습니다. 여기서 문제는 각 data.frame이 행과 열 수의 관점에서 다르지만 모두 핵심 변수 ( 아래에서 호출 "var1"
하고 "var2"
코드)를 공유한다는 것 입니다. data.frames 가 열 측면에서 동일 rbind
하다면 plyr의 rbind.fill 이 작업을 수행 할 수는 있지만이 데이터의 경우는 아닙니다.
이 merge
명령은 2 data.frame에서만 작동 하기 때문에 아이디어를 얻기 위해 인터넷을 사용했습니다. 나는 여기 에서 이것을 얻었고 , 이것은 R 2.7.2에서 완벽하게 작동했습니다.
merge.rec <- function(.list, ...){
if(length(.list)==1) return(.list[[1]])
Recall(c(list(merge(.list[[1]], .list[[2]], ...)), .list[-(1:2)]), ...)
}
그리고 함수를 다음과 같이 호출합니다.
df <- merge.rec(my.list, by.x = c("var1", "var2"),
by.y = c("var1", "var2"), all = T, suffixes=c("", ""))
그러나 2.11 및 2.12를 포함하여 2.7.2 이후의 모든 R 버전에서이 코드는 다음 오류와 함께 실패합니다.
Error in match.names(clabs, names(xi)) :
names do not match previous names
(우연히도 다른 곳에서는 이 오류 에 대한 해결책이 없습니다.)
이 문제를 해결할 방법이 있습니까?
답변
또 다른 질문 은 R에서 dplyr을 사용하여 다중 왼쪽 조인을 수행하는 방법을 구체적으로 물었습니다 . 질문은이 질문과 중복으로 표시되어 있으므로 아래 3 개의 샘플 데이터 프레임을 사용하여 여기에 대답하십시오.
x <- data.frame(i = c("a","b","c"), j = 1:3, stringsAsFactors=FALSE)
y <- data.frame(i = c("b","c","d"), k = 4:6, stringsAsFactors=FALSE)
z <- data.frame(i = c("c","d","a"), l = 7:9, stringsAsFactors=FALSE)
2018 년 6 월 업데이트 : 병합을 수행하는 세 가지 방법을 나타내는 세 가지 섹션으로 답변을 나누었습니다. purrr
이미 tidyverse 패키지 를 사용하고 있다면 그 방법 을 사용하고 싶을 것입니다 . 아래의 비교를 위해 동일한 샘플 데이터 세트를 사용하는 기본 R 버전을 찾을 수 있습니다.
1) 패키지 reduce
에서 함께 참여하십시오 purrr
.
purrr
패키지가 제공 reduce
간결한 구문을 보유 기능 :
library(tidyverse)
list(x, y, z) %>% reduce(left_join, by = "i")
# A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <int>
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
당신은 또한 같은 같은 다른 조인을 수행 할 수 있습니다 full_join
또는 inner_join
:
list(x, y, z) %>% reduce(full_join, by = "i")
# A tibble: 4 x 4
# i j k l
# <chr> <int> <int> <int>
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
# 4 d NA 6 8
list(x, y, z) %>% reduce(inner_join, by = "i")
# A tibble: 1 x 4
# i j k l
# <chr> <int> <int> <int>
# 1 c 3 5 7
2) dplyr::left_join()
기본 R Reduce()
:
list(x,y,z) %>%
Reduce(function(dtf1,dtf2) left_join(dtf1,dtf2,by="i"), .)
# i j k l
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
3)베이스 R이 merge()
있는베이스 R Reduce()
:
그리고 비교를 위해 왼쪽 조인의 기본 R 버전이 있습니다.
Reduce(function(dtf1, dtf2) merge(dtf1, dtf2, by = "i", all.x = TRUE),
list(x,y,z))
# i j k l
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
답변
감소는 이것을 매우 쉽게 만듭니다.
merged.data.frame = Reduce(function(...) merge(..., all=T), list.of.data.frames)
다음은 일부 모의 데이터를 사용하는 완전한 예입니다.
set.seed(1)
list.of.data.frames = list(data.frame(x=1:10, a=1:10), data.frame(x=5:14, b=11:20), data.frame(x=sample(20, 10), y=runif(10)))
merged.data.frame = Reduce(function(...) merge(..., all=T), list.of.data.frames)
tail(merged.data.frame)
# x a b y
#12 12 NA 18 NA
#13 13 NA 19 NA
#14 14 NA 20 0.4976992
#15 15 NA NA 0.7176185
#16 16 NA NA 0.3841037
#17 19 NA NA 0.3800352
다음은 이러한 데이터 를 사용 하여 복제 하는 예입니다 my.list
.
merged.data.frame = Reduce(function(...) merge(..., by=match.by, all=T), my.list)
merged.data.frame[, 1:12]
# matchname party st district chamber senate1993 name.x v2.x v3.x v4.x senate1994 name.y
#1 ALGIERE 200 RI 026 S NA <NA> NA NA NA NA <NA>
#2 ALVES 100 RI 019 S NA <NA> NA NA NA NA <NA>
#3 BADEAU 100 RI 032 S NA <NA> NA NA NA NA <NA>
참고 : 이것은 아마도 버그 인 것 같습니다 merge
. 문제는 일치하지 않는 겹치는 이름을 처리하기 위해 접미사를 추가하면 실제로 접미사를 고유하게 만든다는 확인이 없다는 것입니다. 특정 시점에서 사용 [.data.frame
하는 하지 make.unique
(가) 원인이 이름을 rbind
실패합니다.
# first merge will end up with 'name.x' & 'name.y'
merge(my.list[[1]], my.list[[2]], by=match.by, all=T)
# [1] matchname party st district chamber senate1993 name.x
# [8] votes.year.x senate1994 name.y votes.year.y
#<0 rows> (or 0-length row.names)
# as there is no clash, we retain 'name.x' & 'name.y' and get 'name' again
merge(merge(my.list[[1]], my.list[[2]], by=match.by, all=T), my.list[[3]], by=match.by, all=T)
# [1] matchname party st district chamber senate1993 name.x
# [8] votes.year.x senate1994 name.y votes.year.y senate1995 name votes.year
#<0 rows> (or 0-length row.names)
# the next merge will fail as 'name' will get renamed to a pre-existing field.
수정하는 가장 쉬운 방법은 중복 필드 (여기서 많은 항목)의 필드 이름을 변경하지 않는 것 merge
입니다. 예 :
my.list2 = Map(function(x, i) setNames(x, ifelse(names(x) %in% match.by,
names(x), sprintf('%s.%d', names(x), i))), my.list, seq_along(my.list))
merge
/는 Reduce
잘 작동 후 것이다.
답변
패키지 merge_all
에서 사용할 수 있습니다 reshape
. 인수 를 merge
사용하여 매개 변수를 전달할 수 있습니다...
reshape::merge_all(list_of_dataframes, ...)
답변
재귀를 사용하여이 작업을 수행 할 수 있습니다. 다음을 확인하지는 않았지만 올바른 아이디어를 제공해야합니다.
MergeListOfDf = function( data , ... )
{
if ( length( data ) == 2 )
{
return( merge( data[[ 1 ]] , data[[ 2 ]] , ... ) )
}
return( merge( MergeListOfDf( data[ -1 ] , ... ) , data[[ 1 ]] , ... ) )
}
답변
@PaulRougieux의 데이터 예제를 재사용하겠습니다.
x <- data_frame(i = c("a","b","c"), j = 1:3)
y <- data_frame(i = c("b","c","d"), k = 4:6)
z <- data_frame(i = c("c","d","a"), l = 7:9)
여기에 사용 짧고 달콤한 해결책 purrr
및tidyr
library(tidyverse)
list(x, y, z) %>%
map_df(gather, key=key, value=value, -i) %>%
spread(key, value)
답변
eat
내 패키지 safejoin 의 기능 에는 그러한 기능이 있습니다 .data.frames 목록을 두 번째 입력으로 제공하면 첫 번째 입력에 재귀 적으로 결합됩니다.
허용 된 답변 데이터를 차용 및 확장 :
x <- data_frame(i = c("a","b","c"), j = 1:3)
y <- data_frame(i = c("b","c","d"), k = 4:6)
z <- data_frame(i = c("c","d","a"), l = 7:9)
z2 <- data_frame(i = c("a","b","c"), l = rep(100L,3),l2 = rep(100L,3)) # for later
# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
eat(x, list(y,z), .by = "i")
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <int>
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
모든 열을 사용할 필요는 없습니다. tidyselect 에서 select helper를 사용하여 선택할 수 있습니다 ( .x
모든 .x
열 에서 시작하여 유지됨).
eat(x, list(y,z), starts_with("l") ,.by = "i")
# # A tibble: 3 x 3
# i j l
# <chr> <int> <int>
# 1 a 1 9
# 2 b 2 NA
# 3 c 3 7
또는 특정 것을 제거하십시오.
eat(x, list(y,z), -starts_with("l") ,.by = "i")
# # A tibble: 3 x 3
# i j k
# <chr> <int> <int>
# 1 a 1 NA
# 2 b 2 4
# 3 c 3 5
목록의 이름이 지정되면 이름이 접두사로 사용됩니다.
eat(x, dplyr::lst(y,z), .by = "i")
# # A tibble: 3 x 4
# i j y_k z_l
# <chr> <int> <int> <int>
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
열이 충돌하면 .conflict
인수를 사용하여 예를 들어 첫 번째 / 두 번째 열을 가져 와서 추가, 통합 또는 중첩하여 해결할 수 있습니다.
먼저 유지 :
eat(x, list(y, z, z2), .by = "i", .conflict = ~.x)
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <int>
# 1 a 1 NA 9
# 2 b 2 4 NA
# 3 c 3 5 7
마지막으로 유지 :
eat(x, list(y, z, z2), .by = "i", .conflict = ~.y)
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <dbl>
# 1 a 1 NA 100
# 2 b 2 4 100
# 3 c 3 5 100
더하다:
eat(x, list(y, z, z2), .by = "i", .conflict = `+`)
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <dbl>
# 1 a 1 NA 109
# 2 b 2 4 NA
# 3 c 3 5 107
합병 :
eat(x, list(y, z, z2), .by = "i", .conflict = dplyr::coalesce)
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <int> <dbl>
# 1 a 1 NA 9
# 2 b 2 4 100
# 3 c 3 5 7
둥지:
eat(x, list(y, z, z2), .by = "i", .conflict = ~tibble(first=.x, second=.y))
# # A tibble: 3 x 4
# i j k l$first $second
# <chr> <int> <int> <int> <int>
# 1 a 1 NA 9 100
# 2 b 2 4 NA 100
# 3 c 3 5 7 100
NA
.fill
인수 를 사용하여 값을 대체 할 수 있습니다 .
eat(x, list(y, z), .by = "i", .fill = 0)
# # A tibble: 3 x 4
# i j k l
# <chr> <int> <dbl> <dbl>
# 1 a 1 0 9
# 2 b 2 4 0
# 3 c 3 5 7
기본적으로는 향상된 것 left_join
하지만 모든 dplyr이 관통 지원 조인 .mode
인수, 퍼지도를 통해 지원됩니다 조인 match_fun
인수 (이 패키지 주위에 싸여 fuzzyjoin
) 또는 같은 수식을주고 ~ X("var1") > Y("var2") & X("var3") < Y("var4")
받는
by
인수입니다.
답변
공통 ID 열이없는 데이터 프레임 목록이 있습니다.
많은 df에 대한 데이터가 누락되었습니다. 널값이있었습니다. 데이터 프레임은 테이블 함수를 사용하여 생성되었습니다. Reduce, Merging, rbind, rbind.fill 등은 저의 목표에 도움이되지 못했습니다. 내 목표는 누락 된 데이터 및 공통 ID 열과 관련이없는 이해할 수있는 병합 된 데이터 프레임을 생성하는 것이 었습니다.
따라서 다음과 같은 기능을 수행했습니다. 이 기능은 누군가에게 도움이 될 수 있습니다.
##########################################################
#### Dependencies #####
##########################################################
# Depends on Base R only
##########################################################
#### Example DF #####
##########################################################
# Example df
ex_df <- cbind(c( seq(1, 10, 1), rep("NA", 0), seq(1,10, 1) ),
c( seq(1, 7, 1), rep("NA", 3), seq(1, 12, 1) ),
c( seq(1, 3, 1), rep("NA", 7), seq(1, 5, 1), rep("NA", 5) ))
# Making colnames and rownames
colnames(ex_df) <- 1:dim(ex_df)[2]
rownames(ex_df) <- 1:dim(ex_df)[1]
# Making an unequal list of dfs,
# without a common id column
list_of_df <- apply(ex_df=="NA", 2, ( table) )
그것은 기능을 따르고있다
##########################################################
#### The function #####
##########################################################
# The function to rbind it
rbind_null_df_lists <- function ( list_of_dfs ) {
length_df <- do.call(rbind, (lapply( list_of_dfs, function(x) length(x))))
max_no <- max(length_df[,1])
max_df <- length_df[max(length_df),]
name_df <- names(length_df[length_df== max_no,][1])
names_list <- names(list_of_dfs[ name_df][[1]])
df_dfs <- list()
for (i in 1:max_no ) {
df_dfs[[i]] <- do.call(rbind, lapply(1:length(list_of_dfs), function(x) list_of_dfs[[x]][i]))
}
df_cbind <- do.call( cbind, df_dfs )
rownames( df_cbind ) <- rownames (length_df)
colnames( df_cbind ) <- names_list
df_cbind
}
예제 실행
##########################################################
#### Running the example #####
##########################################################
rbind_null_df_lists ( list_of_df )