我有一个关于在R中使用data.frame进行合并的特定类型的问题(发现了很多类似的问题,但无法解决我的特定问题)
假设我有两个数据帧,每个数据帧的两个列分别为X1,X2:
df1 =
X1 X2
1 '01.01.2000' 4
2 '01.01.2001' 5
3 '01.01.2002' 6
df2 =
X1 X2
1 '01.01.2002' 8
2 '01.01.2003' 9
3 '01.01.2004' 10
我想要的是根据以下规则合并的数据框:
X1
中的值仅在df1
中,请使用X2
中的df1
的值X1
和df1
中的df2
中的值都使用X2
中的df2
的值X1
中的值仅在df2
中,请使用X2
中的df2
的值对于以上df1
和df2
,这意味着:
dfMerged =
X1 X2
1 '01.01.2000' 4
2 '01.01.2001' 5
3 '01.01.2002' 8
4 '01.01.2003' 9
5 '01.01.2004' 10
当前,我正在使用一种非常慢的解决方案,方法是先合并然后遍历所有行。还尝试了使用dplyr :: Union等的各种方法,但是找不到合适的解决方案。 任何帮助将不胜感激!
答案 0 :(得分:4)
您可以使用以下内容。它仅行绑定data.frames,如果重复(基于X1),则df1的行将被删除。
library(dplyr)
df1 <- data.frame(X1 = c("01.01.2000", "01.01.2001", "01.01.2002"),
X2 = c(4, 5, 6), stringsAsFactors = F)
df2 <- data.frame(X1 = c("01.01.2002", "01.01.2003", "01.01.2004"),
X2 = c(8, 9, 10), stringsAsFactors = F)
dfMerged <- bind_rows(df2, df1) %>%
distinct(X1, .keep_all = TRUE) %>%
arrange(X1, X2)
答案 1 :(得分:3)
数据
df1 <- structure(list(X1 = c("01.01.2000", "01.01.2001", "01.01.2002"),
X2 = 4:6),
class = "data.frame",
row.names = c(NA, -3L))
df2 <- structure(list(X1 = c("01.01.2002", "01.01.2003", "01.01.2004"),
X2 = 8:10),
class = "data.frame",
row.names = c(NA, -3L))
代码
library(dplyr)
full_join(df1, df2, by = "X1") %>%
mutate(X2 = case_when(!is.na(X2.x) & !is.na(X2.y) ~ X2.y,
is.na(X2.y) ~ X2.x,
is.na(X2.x) ~ X2.y)) %>%
select(X1, X2)
说明
full_join
,并以X1
作为连接列。这将创建列X2.x
和X2.y
,它们将包含相应数据集的X2值。mutate
的简单应用就是根据您给出的规则选择合适的列。基准
distinct
解决方案无论如何都快了3
倍,如以下基准所示:
library(tidyverse)
library(microbenchmark)
make_data_frame <- function(n, percent_matching = .1) {
ids_a <- ids_b <- paste0("ID_", seq.int(n))
non_matching_ids <- sample(n, round(n * (1 - percent_matching), 0))
ids_b[non_matching_ids] <- paste(ids_b[non_matching_ids], "b", sep = "_")
list(A = data.frame(X1 = ids_a, X2 = "a", stringsAsFactors = FALSE),
B = data.frame(X1 = ids_b, X2 = "b", stringsAsFactors = FALSE))
}
.distinct <- function(dfs) {
bind_rows(dfs$B, dfs$A) %>%
distinct(X1, .keep_all = TRUE)
}
.join <- function(dfs) {
full_join(dfs$A, dfs$B, by = "X1") %>%
mutate(X2 = case_when(!is.na(X2.x) & !is.na(X2.y) ~ X2.y,
is.na(X2.y) ~ X2.x,
is.na(X2.x) ~ X2.y))
}
scenarios <- expand.grid(n = c(1e4, 1e5, 1e6),
percent_matching = c(.1, .5, .9))
all_data <- pmap(scenarios, make_data_frame)
all_mb <- map(all_data, ~ microbenchmark(.distinct(.x), .join(.x)))
map_dfr(seq.int(NROW(scenarios)), function(i) {
mdat <- scenarios[i, ]
my_summary <- summary(all_mb[[i]])
rownames(mdat) <- NULL
rownames(my_summary) <- NULL
cbind(mdat, my_summary)
}) %>%
select(n, percent_matching, expr, mean)
# n percent_matching expr mean
# 1 1e+04 0.1 .distinct(.x) 4.975013
# 2 1e+04 0.1 .join(.x) 12.587072
# 3 1e+05 0.1 .distinct(.x) 59.577142
# 4 1e+05 0.1 .join(.x) 149.987451
# 5 1e+06 0.1 .distinct(.x) 1.158597
# 6 1e+06 0.1 .join(.x) 2.699003
# 7 1e+04 0.5 .distinct(.x) 4.485196
# 8 1e+04 0.5 .join(.x) 11.902656
# 9 1e+05 0.5 .distinct(.x) 46.660016
# 10 1e+05 0.5 .join(.x) 132.180758
# 11 1e+06 0.5 .distinct(.x) 913.503111
# 12 1e+06 0.5 .join(.x) 2148.531600
# 13 1e+04 0.9 .distinct(.x) 4.299905
# 14 1e+04 0.9 .join(.x) 12.731292
# 15 1e+05 0.9 .distinct(.x) 37.558069
# 16 1e+05 0.9 .join(.x) 111.428117
# 17 1e+06 0.9 .distinct(.x) 458.030035
# 18 1e+06 0.9 .join(.x) 1458.408847