#r #join #replace #data.table #subset
#r #Присоединиться #заменить #data.table #подмножество
Вопрос:
У меня есть набор данных, состоящий из пар id-name. Эти пары могут появляться несколько раз. В некоторых строках отсутствует значение в столбце name, в других отсутствует идентификатор:
id_name = data.table(stringsAsFactors=FALSE,
id = c("x123", "xy234","x123",NA,"z123","y123","d654","d654"),
name = c("john", "mary", NA,"mary","bob","bob", "john",NA)
)
Я хотел бы заменить только значения NA в одном столбце на (не пропущенное) значение из другой строки, используя другой столбец в качестве значения поиска. Результат должен быть:
id name
1: x123 john
2: xy234 mary
3: x123 john
4: xy234 mary
5: z123 bob
6: y123 bob
7: d654 john
8: d654 john
Каков идиоматический способ достижения этого, способ data.table? Следующий подход для обновления только столбца name не приводит к ошибке, но он также не обновляет набор данных :
id_name[is.na(name)][id_name[!is.na(name)], on="id", name:=i.name]
> id_name
id name
1: x123 john
2: xy234 mary
3: x123 <NA>
4: <NA> mary
5: z123 bob
6: y123 bob
7: d654 john
8: d654 <NA>
Однако работает только подмножество и соединение без обновления:
id_name[is.na(name)][id_name[!is.na(name)], on="id",nomatch=0L]
id name i.name
1: x123 <NA> john
2: d654 <NA> john
Обновить
Обновлен MRE, чтобы прояснить, что некоторые имена могут быть связаны с 2 идентификаторами. Оба идентификатора должны быть сохранены.
Ответ №1:
Я думаю, вы ищете:
id_name[is.na(name), name :=
id_name[!is.na(name)][.SD, on=.(id), x.name]
]
id_name[is.na(id), id :=
id_name[!is.na(id)][.SD, on=.(name), mult="first", x.id]
]
id_name
Комментарии:
1. Мне нравится ваше решение, потому что это чистый подход data.table
Ответ №2:
Мы можем сгруппировать по ‘name’, ‘id’ и заменить элементы NA в ‘id’ на первое значение, отличное от NA
id_name[, id := id[!is.na(id)][1], name]
id_name[, name := name[!is.na(name)], id]
-вывод
id_name
# id name
#1: x123 john
#2: xy234 marry
#3: x123 john
#4: xy234 marry
Обновить
Мы можем использовать fill
из tidyr
library(tidyr)
id_name1 <- id_name[, fill(.SD, id), name][, fill(.SD, name) , id]
id_name1
# id name
#1: x123 john
#2: x123 john
#3: d654 john
#4: d654 john
#5: xy234 mary
#6: xy234 mary
#7: z123 bob
#8: y123 bob
Комментарии:
1. Хотя этот подход обновляет отсутствующие значения, он также удаляет любые дополнительные записи, которые могут существовать для того же идентификатора / имени. Подход, который я ищу, должен обновлять только записи с пропущенными значениями, не отбрасывая другие записи.
2. @MariusPetruc не могли бы вы обновить свой пример более общим
Ответ №3:
Вы можете использовать zoo
‘s na.locf
для заполнения недостающих значений.
library(zoo)
library(data.table)
id_name[, id := na.locf(id), name]
id_name[, name := na.locf(name), id]
id_name
# id name
#1: x123 john
#2: xy234 marry
#3: x123 john
#4: xy234 marry
Комментарии:
1. data.table уже имеет функцию fillna, поэтому дополнительные пакеты не нужны
2. @jangorecki Хорошо… Я этого не знал, спасибо. Однако, похоже, это работает только для числовых значений, а не для символьных значений?