как использовать merge () для обновления таблицы в R - PullRequest
19 голосов
/ 07 июля 2010

Я пытаюсь выяснить, как использовать 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. Есть ли простой способ сделать это?

Ответы [ 6 ]

7 голосов
/ 07 июля 2010

Разве 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 голосов
/ 07 февраля 2019

Оптимальное решение с использованием 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..

2 голосов
/ 17 августа 2016

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

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: обновление с двумя таблицами

0 голосов
/ 27 сентября 2017

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

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
0 голосов
/ 16 января 2017

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

  1. Удалить NA из первого блока данных

  2. Используйте 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
0 голосов
/ 07 июля 2010

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

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

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