Как использовать merge() для обновления таблицы в R

Я пытаюсь выяснить, как использовать merge() для обновления базы данных.

Вот пример. Возьмем, например, фрейм данных foo

foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA))

Что имеет следующие значения

index value
1     a   100
2     b   101
3     c    NA
4     d    NA

И кадр данных bar

bar <- data.frame(index=c('c', 'd'), value=c(200, 201))

Что имеет следующие значения:

 index value
1     c   200
2     d   201

Когда я запускаю следующую функцию merge() для обновления значений для c и d

merge(foo, bar, by='index', all=T)

В результате этого результата:

 index value.x value.y
1     a     100      NA
2     b     101      NA
3     c      NA     200
4     d      NA     201

Мне нужен вывод merge(), чтобы избежать создания в этом конкретном примере value.x и value.y, но сохранить только исходный столбец value. Простой способ сделать это

Ответы

Ответ 1

Не связывает ли merge() столбцы вместе? Работает ли replace()?

foo$value <- replace(foo$value, foo$index %in% bar$index, bar$value)

или match(), поэтому порядок имеет значение

foo$value[match(bar$index, foo$index)] <- bar$value

Ответ 2

Я также хотел бы представить sql-решение, используя библиотеку sqldf и встроенную базу данных sqlite R. Мне нравится простота, аккуратность и мощь sql.
Точность: поскольку я могу точно определить, какой объект = строки я хочу изменить без учета порядка data.frame(foo.id = bar.id).
Power: в WHERE после SET и WHERE (третья строка) я могу определить все условия, которые я хочу рассмотреть для обновления.
Простота: синтаксис более читабельен, чем использование индекса в векторах, матрицах или кадрах данных.

library(sqldf)

# I changed index to id since index does not work. 
#   Obviously index is a key word in sqlite.

(foo <- data.frame(id=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA)))
(bar <- data.frame(id=c('c', 'd'), value=c(200, 201)))

sqldf(c(paste("UPDATE foo"
             ," SET value = (SELECT bar.value FROM bar WHERE foo.id = bar.id)"
             ," WHERE value IS NULL"
             )
        , " SELECT * FROM main.foo"
    )
)

Что дает

  id value
1  a   100
2  b   101
3  c   200
4  d   201

Похожие проблемы:
r эквивалент обновления sql?
R sqlite: обновление с двумя таблицами

Ответ 3

merge() объединяется только в новые данные. Например, если у вас есть набор данных среднего дохода для нескольких городов и отдельный набор данных населения этих городов, вы бы использовали merge() для объединения одного набора данных в другой.

Как и apeescape, replace(), вероятно, вы хотите.

Ответ 4

Другим подходом может быть:

  • Удалите НС из первого фрейма данных

  • Используйте rbind для добавления данных вместо использования слияния:

Это исходные два кадра данных:

foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA))
bar <- data.frame(index=c('c', 'd'), value=c(200, 201))

(1) Используйте отрицание is.na для удаления NA:

foo_new <- foo[!is.na(foo$value),]

(2) Привяжите кадры данных, и вы получите ответ, который вы искали

new_df <- rbind(foo_new,bar)

            new_df
            index value
            1     a   100
            2     b   101
            3     c   200
            4     d   201

Ответ 5

Я думаю, что самый простой способ - "отметить" значение, которое необходимо обновить до слияния.

bar$update <- TRUE
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update"))
foo[!is.na(foo$update),]$value <- foo[!is.na(foo$update),]$value.update
foo$value.update <- NULL
foo$update <- NULL

Было бы быстрее использовать 'data.table'

library(data.table)
foo <- as.data.table(foo)
bar <- as.data.table(bar)
bar[, update:=TRUE]
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update"))
foo[!is.na(update),value:=value.update]
foo[, c("value.update","update"):=NULL]
foo

   index value
1:     a   100
2:     b   101
3:     c   200
4:     d   201

Ответ 6

Оптимальное решение с использованием data.table

library(data.table)
setDT(foo)
setDT(bar)
foo[bar, on="index", value:=i.value]
foo
#   index value
#1:     a   100
#2:     b   101
#3:     c   200
#4:     d   201

Первый аргумент в [ data.table метод назван i, таким образом, мы можем сослаться на колонку из таблицы в i аргумента с помощью i. префикс.

Ответ 7

na.omit этого вы можете рассмотреть логику union из пакета dplyr + base na.omit:

require(dplyr)
na.omit(dplyr::union(foo, bar))
      index value
    1     b   101
    4     a   100
    5     c   200
    6     d   201