Соединение фреймов данных без возврата всех соответствующих комбинаций - PullRequest
0 голосов
/ 16 января 2019

У меня есть list из data.frame с (в этом примере только 2):

set.seed(1)

df1 <- data.frame(id = sample(LETTERS,50,replace=T), val = rnorm(50), val1 = rnorm(50), stringsAsFactors = F)
df2 <- data.frame(id = sample(LETTERS,30,replace=T), val = rnorm(30), val2 = rnorm(30), stringsAsFactors = F)

df.list <- list(df1,df2)

Я хочу join их в один data.frame только подмножеством имен общих столбцов, в данном случае id.

Если я использую:

library(dplyr)
df <- df.list %>% purrr::reduce(dplyr::inner_join,by="id")

Имена общих столбцов, к которым я не присоединяюсь, видоизменяются с помощью x и y:

  id       val.x       val1     val.y       val2
1  G -0.05612874  0.2914462  2.087167  0.7876396
2  G -0.05612874  0.2914462 -0.255027  1.4411577
3  J -0.15579551 -0.4432919 -1.286301  1.0273924

На самом деле, для имен общих столбцов, к которым я не присоединяюсь, достаточно выбрать их из одного элемента data.frame в списке - независимо от того, существуют ли они в WRT к объединенному id.

Я не знаю заранее названий этих общих столбцов, но это не сложно выяснить:

например:.

df.list.colnames <- unlist(lapply(df.list,function(l) colnames(l %>% dplyr::select(-id))))
df.list.colnames <- table(df.list.colnames)
repeating.colnames <- names(df.list.colnames)[which(df.list.colnames > 1)]

Что затем позволит мне отделить их от data.frame в list:

repeating.colnames.df <- do.call(rbind,lapply(df.list,function(r) r %>% dplyr::select_(.dots = c("id",repeating.colnames)))) %>%
  unique()

Затем я могу присоединиться к списку data.frame с исключением этих столбцов:

А затем присоединитесь к ним, как указано выше:

for(r in 1:length(df.list)) df.list[[r]] <- df.list[[r]] %>% dplyr::select_(.dots = paste0("-",repeating.colnames))
df <- df.list %>% purrr::reduce(dplyr::inner_join,by="id")

А теперь мне осталось добавить к этому repeating.colnames.df. Я не знаю ни одного join в dplyr, который не будет возвращать все комбинации между df и repeating.colnames.df, поэтому мне кажется, что все, что я могу сделать, это apply над каждым df$id, выбрать первое совпадение в repeating.colnames.df и объедините результат с df.

Есть ли что-нибудь менее громоздкое в этой ситуации?

Ответы [ 2 ]

0 голосов
/ 16 января 2019

Вы можете просто избавиться от дубликатов столбцов в одном из фреймов данных, если вы говорите, что вам на самом деле их не интересует, и просто используете base::merge:

set.seed(1)

df1 <- data.frame(id = sample(LETTERS,50,replace=T), val = rnorm(50), val1 = rnorm(50), stringsAsFactors = F)
df2 <- data.frame(id = sample(LETTERS,30,replace=T), val = rnorm(30), val2 = rnorm(30), stringsAsFactors = F)


duplicates = names(df1) == names(df2) & names(df1) !="id"

df2 = df2[,!duplicates]
df12 = base::merge.data.frame(df1, df2, by = "id")
head(df12)
0 голосов
/ 16 января 2019

Если я следовал правильно, я думаю, что вы можете справиться с этим, написав пользовательскую функцию для передачи в reduce, которая идентифицирует общие имена столбцов (исключая присоединяемые столбцы) и исключает эти столбцы из «второй» таблицы в слиянии , Когда reduce работает по списку, функция «накапливает» уникальные столбцы, по умолчанию столбцы в «самой левой» таблице.

Примерно так:

library(dplyr)
library(purrr)
set.seed(1)
df1 <- data.frame(id = sample(LETTERS,50,replace=T), val = rnorm(50), val1 = rnorm(50), stringsAsFactors = F)
df2 <- data.frame(id = sample(LETTERS,30,replace=T), val = rnorm(30), val2 = rnorm(30), stringsAsFactors = F)
df.list <- list(df1,df2)

fun <- function(df1, df2, by_col = "id"){
  df1_names <- names(df1)
  df2_names <- names(df2)
  dup_cols <- intersect(df1_names[!df1_names %in% by_col], df2_names[!df2_names %in% by_col])
  out <- dplyr::inner_join(df1, df2[, !(df2_names %in% dup_cols)], by = by_col)
  return(out)
}

df_chase <- df.list %>% reduce(fun,by_col="id")

Создано в 2019-01-15 пакетом Представления (v0.2.1)

Если я сравню df_chase с вашим окончательным решением, я получу тот же ответ:

> all.equal(df_chase, df_orig)
[1] TRUE
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...