Объединить фреймы данных без функции слияния - PullRequest
0 голосов
/ 28 февраля 2020

У меня есть два фрейма данных с именем height.txt

ID:     1 2 3 4 5
Height: 67 60 62 55 69

, а следующий фрейм данных - weight.txt

ID: 1 2 4 5 6
Weight: 110 123 150 170 185

Цель состоит в том, чтобы объединить эти два фрейма данных без используя функцию merge() в R, и результат должен быть в изображении. Как бы я это сделал? Это для практики, я знаю, merge() добивается цели, но я должен делать это без нее, это для класса.

Output

Редактировать:

Данные в формате копирования и вставки.

ID <- scan(text = "1 2 3 4 5")
Height <- scan(text = "67 60 62 55 69")
df1 <- data.frame(ID, Height)

ID <- scan(text = "1 2 4 5 6")
Weight <- scan(text = "110 123 150 170 185")
df2 <- data.frame(ID, Weight)

Ответы [ 2 ]

1 голос
/ 28 февраля 2020

Я использовал cbind после rbind ввода отсутствующих идентификаторов из каждого фрейма данных и сортировки по идентификатору.

df1_ <- rbind(df1, data.frame(ID=setdiff(df2$ID, df1$ID), Height=NA))
df2_ <- rbind(df2, data.frame(ID=setdiff(df1$ID, df2$ID), Weight=NA))
cbind(df1_[order(df1_$ID),], df2_[order(df2_$ID), -1, drop=FALSE])

  ID Height Weight
1  1     67    110
2  2     60    123
3  3     62     NA
4  4     55    150
5  5     69    170
6  6     NA    185

Редактировать : Обобщение, при котором имена столбцов не требуются (кроме идентификатора столбца "by")

n1 <- setdiff(df1$ID, df2$ID); n1
n2 <- setdiff(df2$ID, df1$ID); n2

df1a <- df1[rep(nrow(df1)+1, length(n1)),]; df1a
df2a <- df2[rep(nrow(df2)+1, length(n2)),]; df2a

df1a$ID <- n2
df2a$ID <- n1

df1_ <- rbind(df1, df1a)
df2_ <- rbind(df2, df2a)

res <- cbind(df1_[order(df1_$ID),], df2_[order(df2_$ID), -1, drop=FALSE])
rownames(res) <- 1:nrow(res)
res

   ID Height Weight
1   1     67    110
2   2     60    123
3   3     62     NA
4   4     55    150
5   5     69    170
NA  6     NA    185

Редактировать 2 : Использование rbind.fill из пакета plyr :

library(plyr)

df1_ <- rbind.fill(df1, data.frame(ID=setdiff(df2$ID, df1$ID)))
df2_ <- rbind.fill(df2, data.frame(ID=setdiff(df1$ID, df2$ID)))

res <- cbind(df1_[order(df1_$ID),], df2_[order(df2_$ID), -1, drop=FALSE])

identical(res, merge(df1, df2, all=TRUE))
# TRUE
1 голос
/ 28 февраля 2020

Это простое повторное использование match.

  1. Создайте data.frame со всеми элементами общего столбца, ID, без повторений.
  2. match ID каждого из фреймов данных с ID результата res.
  3. Назначьте другие столбцы.

Не забудьте создать каждый других столбцов, прежде чем присваивать им значения.

res <- data.frame(ID = unique(c(df1$ID, df2$ID)))

i <- match(df1$ID, res$ID)
j <- na.omit(match(res$ID, df1$ID))
res$Height <- NA
res$Height[i] <- df1$Height[j]

i <- match(df2$ID, res$ID)
j <- na.omit(match(res$ID, df2$ID))
res$Weight <- NA
res$Weight[i] <- df2$Weight[j]


res
#  ID Height Weight
#1  1     67    110
#2  2     60    123
#3  3     62     NA
#4  4     55    150
#5  5     69    170
#6  6     NA    185

identical(res, merge(df1, df2, all = TRUE))
#[1] TRUE

Редактировать.

Ответ на вопрос в комментарии о том, насколько общим является это решение. From help("merge"):

Details

merge является обобщенной функцией c, основным методом которой является фреймы данных: метод по умолчанию приводит свои аргументы к фреймам данных и вызывает " data.frame "method.

Метод merge.data.frame в R 3.6.2 имеет длину 158 строк кода, это решение вообще не является общим.

Редактировать 2.

Функция, обобщающая приведенный выше код, может выполнять следующие действия.

merge_by_one_col <- function(X, Y, col = "ID"){
  common <- unique(c(X[[col]], Y[[col]]))
  res <- data.frame(common)
  names(res) <- col

  i <- match(X[[col]], res[[col]])
  j <- na.omit(match(res[[col]], X[[col]]))
  for(new in setdiff(names(X), col)){
    res[[new]] <- NA
    res[[new]][i] <- X[[new]][j]
  }

  i <- match(Y[[col]], res[[col]])
  j <- na.omit(match(res[[col]], Y[[col]]))
  for(new in setdiff(names(Y), names(res))){
    res[[new]] <- NA
    res[[new]][i] <- Y[[new]][j]
  }

  res
}

merge_by_one_col(df1, df2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...