Обновите существующий data.frame со значениями из другого, если они отсутствуют - PullRequest
0 голосов
/ 31 мая 2018

Я ищу (1) имя и (2) метод (более чистый) в R (предпочтительно для базы и таблицы данных) из следующих элементов.

Ввод

> d1
  id  x  y
1  1  1 NA
2  2 NA  3
3  3  4 NA
> d2
  id  x  y z
1  4 NA 30 a
2  3 20  2 b
3  2 14 NA c
4  1 15 97 d

(обратите внимание, что фактические фреймы данных имеют сотни столбцов)

Ожидаемый результат :

> d1
  id  x  y z
1  1  1 97 d
2  2 14  3 c
3  3  4  2 b

Данные итекущее решение:

d1 <- data.frame(id = 1:3, x = c(1, NA, 4), y = c(NA, 3, NA))
d2 <- data.frame(id = 4:1, x = c(NA, 20, 14, 15), y = c(30, 2, NA, 97), z = letters[1:4])

for (col in setdiff(names(d1), "id")) {
  # If missing look in d2
  missing <- is.na(d1[[col]])
  d1[missing, col] <- d2[match(d1$id[missing], d2$id), col]
} 
for (col in setdiff(names(d2), names(d1))) {
  # If column missing then add
  d1[[col]] <- d2[match(d1$id, d2$id), col]
}

PS:

Вероятно, этот вопрос уже задавался ранее, но мне не хватает словарного запаса для его поиска.

Ответы [ 3 ]

0 голосов
/ 31 мая 2018

Мы можем использовать data.table с coalesce с dplyr.Создайте vector имен столбцов, которые являются общими ('nm1') и разностью ('nm2') в обоих наборах данных.Преобразовать первый набор данных в «data.table» (setDT(d1)), объединить on столбец «id», назначить (:=) столбцы coalesce d первого и второго (с префиксом i. -если есть общие столбцы), чтобы обновить значения в первом наборе данных

library(data.table)
nm1 <- setdiff(intersect(names(d1), names(d2)), 'id')
nm2 <- setdiff(names(d2), names(d1))
setDT(d1)[d2, c(nm1, nm2) := c(Map(dplyr::coalesce, mget(nm1), 
              mget(paste0("i.", nm1))), mget(nm2)), on = .(id)]
d1
#   id  x  y z
#1:  1  1 97 d
#2:  2 14  3 c
#3:  3  4  2 b
0 голосов
/ 31 мая 2018

Предполагая, что вы работаете с 2 data.frames, вот базовое решение

#expand d1 to have the same columns as d2
d <- merge(d1, d2[, c("id", setdiff(names(d2), names(d1))), drop=FALSE], 
    by="id", all.x=TRUE, all.y=FALSE)

#make sure that d2 also have same number of columns as d1
d2 <- merge(d2, d1[, c("id", setdiff(names(d1), names(d2))), drop=FALSE], 
    by="id", all.x=TRUE, all.y=FALSE)

#align rows and columns to match those in d1
mask <- d2[match(d1$id, d2$id), names(d)]

#replace NAs with those mask
replace(d, is.na(d), mask[is.na(d)])

Если вы не возражаете, мы можем переписать ваш вопрос в общий вопрос о матрице слияния (т.е. любое количество матриц), столбцы, строки), который, как кажется, никогда не задавался.


edit:

Другое решение для base R - это взлом coalesce1a из Как реализоватьэффективно объединить в R

coalesce.mat <- function(...) {
    ans <- ..1  
    for (elt in list(...)[-1]) {
        rn <- match(ans$id, elt$id)
        ans[is.na(ans)] <- elt[rn, names(ans)][is.na(ans)]
    }
    ans         
}

allcols <- Reduce(union, lapply(list(d1, d2), names))
do.call(coalesce.mat, 
    lapply(list(d1, d2), function(x) {
        x[, setdiff(allcols, names(x))] <- NA
        x 
    }))

edit:

возможное data.table решение с использованием coalesce1a из Как эффективно реализовать объединение в R Мартином Морганом.

coalesce1a <- function(...) {
    ans <- ..1
    for (elt in list(...)[-1]) {
        i <- which(is.na(ans))
        ans[i] <- elt[i]
    }
    ans
}

setDT(d1)
setDT(d2)

#melt into long formats and full outer join the 2
mdt <- merge(melt(d1, id.vars="id"), melt(d2, id.vars="id"), by=c("id","variable"), all=TRUE)

#perform a coalesce on vectors
mdt[, value := do.call(coalesce1a, .SD), .SDcols=grep("value", names(mdt), value=TRUE)]

#pivot into original format and subset to those in d1
dcast.data.table(mdt, id ~ variable, value.var="value")[
    d1, .SD, on=.(id)]
0 голосов
/ 31 мая 2018

Вот возможность использования dplyr::left_join:

left_join(d1, d2, by = "id") %>%
    mutate(
        x = ifelse(!is.na(x.x), x.x, x.y),
        y = ifelse(!is.na(y.x), y.x, y.y)) %>%
    select(id, x, y, z)
#  id  x  y z
#1  1  1 97 d
#2  2 14  3 c
#3  3  4  2 b
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...