Ответ 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
Я пытаюсь выяснить, как использовать 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
. Простой способ сделать это
Не связывает ли merge()
столбцы вместе? Работает ли replace()
?
foo$value <- replace(foo$value, foo$index %in% bar$index, bar$value)
или match()
, поэтому порядок имеет значение
foo$value[match(bar$index, foo$index)] <- bar$value
Я также хотел бы представить 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: обновление с двумя таблицами
merge()
объединяется только в новые данные. Например, если у вас есть набор данных среднего дохода для нескольких городов и отдельный набор данных населения этих городов, вы бы использовали merge()
для объединения одного набора данных в другой.
Как и apeescape, replace()
, вероятно, вы хотите.
Другим подходом может быть:
Удалите НС из первого фрейма данных
Используйте 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
Я думаю, что самый простой способ - "отметить" значение, которое необходимо обновить до слияния.
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
Оптимальное решение с использованием 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.
префикс.
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