Подмножество-соединение-замена с использованием R данных.таблица

#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 Хорошо… Я этого не знал, спасибо. Однако, похоже, это работает только для числовых значений, а не для символьных значений?