2010-07-06 2 views
14

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

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

+0

Что результат должен быть в случае каких-либо провалов? –

+1

Вы когда-нибудь получали ответ на этот вопрос? Я ищу решение для этой же проблемы. – Gandalf

+0

Интересно, почему у слияния нет, скажем, параметра 'overwrite = TRUE', который будет срабатывать, когда предоставляется' by'. Для каждого столбца вручную требуется удалить столбцы вручную, когда вы хотите перезапустить слияние. – Valentas

ответ

7

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

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

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

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

Одна морщина с использованием 'replace()' заключается в том, что если порядок в 'bar' не совпадает с порядком в' foo', он не будет работать должным образом. Например, если вы попытаетесь запустить приведенный выше пример после 'bar <- bar [c (2,1),]', конечный результат не будет корректным. – andrewj

+0

Вы правы, как насчет match()? отредактировано выше – apeescape

+0

Да, 'match()' работает для моего примера. На самом деле, оказывается, что мой фактический прецедент более сложный, где я хотел бы сопоставлять несколько столбцов, а не просто простой вектор. Я не думаю, что 'match()' работает, если вы хотите совместить несколько столбцов в кадре данных. – andrewj

0

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

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

2

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

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 equivalent of sql update?
R sqlite: update with two tables

+2

Оператор SQL может работать через несколько строк, поэтому 'paste' не требуется. –

+0

@ Grothendieck Спасибо за эту информацию. – giordano

0

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

  1. Удалите Nas сюда м первого Фрама данных

  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 удалить Nas:

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

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

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 
Смежные вопросы