Объединение / объединение двух фреймов данных с помощью симметричных различий в строках и столбцах - PullRequest
4 голосов
/ 23 сентября 2019

Я хотел бы объединить / объединить два фрейма данных, но игнорируя сходства в строках и столбцах результирующего фрейма данных.Рассмотрим следующий пример:

df1 <- data.frame(
  id = c("a","b","c"),
  a = runif(3,1,9),
  b = runif(3,1,9)
)

df2 <- data.frame(
  df1[1:2,],
  c = runif(2,1,9)
)

В результате получается два фрейма данных, которые имеют ровно четыре ячейки общего (не считая id), поэтому df1[1:2,2:3] == df2[1:2,2:3].Однако они отличаются тем, что df1 в качестве дополнительной строки и df2 имеет дополнительный столбец:

> print(df1)
  id        a        b
1  a 6.396168 4.037320
2  b 4.119025 8.181253
3  c 5.608775 4.219469

> print(df2)
  id        a        b        c
1  a 6.396168 4.037320 2.444122
2  b 4.119025 8.181253 6.444280

Я хочу, чтобы новый фрейм данных состоял из симметричных разностей между этими двумя, поэтому нет дубликатов в строках или столбцах.Ближайший результат, которого я достиг, - это использование dplyr::full_join(df1, df2, by = "id"), но это приводит к дублированию столбцов.

Результат должен выглядеть следующим образом:

  id        a        b        c
1  a 6.396168 4.037320 2.444122
2  b 4.119025 8.181253 6.444280
3  c 5.608775 4.219469       NA

Каков наилучший способ достижения этого динамически?Спасибо

Ответы [ 4 ]

2 голосов
/ 23 сентября 2019

С помощью data.table мы можем присоединиться к 'id' и назначить 'c' из второго набора данных, чтобы создать столбец 'c' в первых данных.По умолчанию несовпадающие элементы будут назначены как NA

library(data.table)
setDT(df1)[df2, c := c, on = .(id)]
df1
#   id        a        b        c
#1:  a 4.601639 1.065642 7.476494
#2:  b 6.065758 6.234421 8.929932
#3:  c 4.000351 7.365717       NA

ПРИМЕЧАНИЕ. Значения отличаются, поскольку не было заданного начального числа


In base R,вариант будет match

df1$c <- df2$c[match(df1$id, df2$id)]

Что касается использования OP * full_join (left_join было бы хорошо на основе примера), хитрость заключается в удалении столбцов, которые не являютсятребуется во втором наборе данных

library(dplyr)
nm1 <- c("id", setdiff(names(df2), names(df1)))
left_join(df1, select(df2, nm1), by = 'id')
0 голосов
/ 23 сентября 2019

База R merge() может достичь этого:

merge(df1, df2, all = TRUE)

  id        a        b        c
1  a 6.396168 4.037320 2.444122
2  b 4.119025 8.181253 6.444280
3  c 5.608775 4.219469       NA
0 голосов
/ 23 сентября 2019

Другой подход, если в одном из фреймов данных есть все нужные вам строки (здесь df2):

library(dplyr)
bind_rows(df2, anti_join(df1, df2))

#Joining, by = c("id", "a", "b")
#  id        a        b        c
#1  a 1.912298 5.792475 6.899253
#2  b 2.537666 1.495075 1.186120
#3  c 5.947766 6.594028       NA
0 голосов
/ 23 сентября 2019

В данном конкретном случае этого будет достаточно

library(sqldf)
sqldf("select * from df1 left natural join df2")
##   id        a        b        c
## 1  a 6.396168 4.037320 2.444122
## 2  b 4.119025 8.181253 6.444280
## 3  c 5.608775 4.219469       NA

или с помощью dplyr:

library(dplyr)
left_join(df1, df2)

, но в целом вам может потребоваться следующее.Обратите внимание, что это совершенно общее.Нам не нужно было указывать имена столбцов или строк ни в приведенном выше, ни в следующем коде, а в следующем коде он симметричен в df1 и df2, поэтому он не полагается на знание структуры любого из них.

sqldf("select * from df1 left natural join df2
union
select * from df2 left natural join df1")
##   id        a        b        c
## 1  a 6.396168 4.037320 2.444122
## 2  b 4.119025 8.181253 6.444280
## 3  c 5.608775 4.219469       NA

или с dplyr.Это даст предупреждение, но все еще работает.Вы можете избежать предупреждения, если id был символом, а не фактором или если вы сначала преобразовали его в символ.

library(dplyr)
rbind(left_join(df1, df2), left_join(df2, df1)) %>% distinct

Примечание

Поскольку в вопросе не использовался set.seed кодсгенерировать ввод невозможно, но мы можем скопировать конкретные df1 и df2, чтобы у нас были те же данные, что и в вопросе.

Lines1 <- "
  id        a        b
1  a 6.396168 4.037320
2  b 4.119025 8.181253
3  c 5.608775 4.219469"
df1 <- read.table(text = Lines1)

Lines2 <- "
  id        a        b        c
1  a 6.396168 4.037320 2.444122
2  b 4.119025 8.181253 6.444280"
df2 <- read.table(text = Lines2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...