合并R中的data.frame

时间:2018-08-27 08:32:41

标签: r dataframe

我有一个关于在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

我想要的是根据以下规则合并的数据框:

  1. 如果X1中的值仅在df1中,请使用X2中的df1的值
  2. 如果X1df1中的df2中的值都使用X2中的df2的值
  3. 如果X1中的值仅在df2中,请使用X2中的df2的值

对于以上df1df2,这意味着:

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等的各种方法,但是找不到合适的解决方案。 任何帮助将不胜感激!

2 个答案:

答案 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)

说明

  1. 首先,您要对两个数据集进行full_join,并以X1作为连接列。这将创建列X2.xX2.y,它们将包含相应数据集的X2值。
  2. 然后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