2016-10-28 2 views
0

У меня есть data.table и нужно сделать некоторые очистки для нескольких значений, которые должны быть уникальными - упрощенный пример должен помочь:Выбор не являющихся `значения NA` из повторяющихся строк с` data.table`

> DT 
    id type 
1: 1 A 
2: 2 X 
3: 3 X 
4: 3 G 
5: 3 NA 
6: 4 D 
7: 5 NA 

проблема у меня есть несколько значений для «типа» за те же ID, или:

> DT[id == 3] 
    id type 
1: 3 X 
2: 3 G 
3: 3 NA 

источник множество значений не имеет значения, но я хотел бы, чтобы очистить это определенным образом: взять последний сообщил значение, если оно не является NA. Таким образом, очистка должна привести к одной строке на ID, а в примере дело будет выглядеть следующим образом:

> DTclean 
    id type 
1: 1 A 
2: 2 X 
3: 3 G 
4: 4 D 
5: 5 NA 

Мой текущий подход сортировать DT по type, так что все NA «s являются первым, а затем используйте duplicated - это приемлемо, но я считаю, что есть лучший метод, плюс, хотя это и не имеет решающего значения, это не всегда берет последнее сообщенное значение. В приведенном выше случае X вместо G.

Это мой текущий подход:

> setorder(DT, type) 
> DTclean <- DT[!duplicated(id, fromLast = T)] 
> DTclean 
    id type 
1: 1 A 
2: 2 X 
3: 3 X 
4: 4 D 
5: 5 NA 

Любые идеи/помощь будут высоко оценены!

+0

Ваш путь кажется прекрасным для меня. Можете ли вы опубликовать этот пример воспроизводимым способом (например, используя 'dput')? – Frank

+1

Кроме того, повторное лечение NA, этот вопрос очень похож на http://stackoverflow.com/q/40097041/ – Frank

+1

@Frank - извинения, добавил ваш очень разумный запрос в пользу других – daRknight

ответ

0

Небольшая вариация вашей идеи должна работать. Концепция является то, что вы хотите отдельный столбец, указывающий только ли или нет «типа» является NA, а не значение, а также сортировать по этому колонку, а затем оригинал ID:

> DT$typena<-is.na(DT$type) 
> setorderv(DT,c('typena','id'),order=c(-1,1)) 
> DT[!duplicated(id,fromLast=T)] 
    id type typena 
1: 5 NA TRUE 
2: 1 A FALSE 
3: 2 X FALSE 
4: 3 G FALSE 
5: 4 D FALSE 

Вы можете затем удалить дополнительный столбец снова если вы не хотите его в пути, присваивая NULL к нему, или сделать все это в одном шаге:

DT[!duplicated(id,fromLast=T),c('id','type'),with=F] 

Вот dput образцовых данных выше:

DT <- structure(list(id = c(1L, 2L, 3L, 3L, 3L, 4L, 5L), type = c("A", 
     "X", "X", "G", NA, "D", NA)), .Names = c("id", "type"), 
     row.names = c(NA, -7L), class = c("data.table", "data.frame")) 
0

Я иду t немного иной подход, который также дает желаемый результат. Вам просто нужны два дополнительных столбца, но это должно быть просто. Идея основана на функциях Row_Number(), доступных в T-SQL.

library(data.table) 
    id <- as.integer(c(1,2,3,3,3,4,5)) 
    type <- as.character(c("A", "X", "X", "G", NA, "D", NA)) 

    DT <- data.table(id,type) 

    DT[, Index := 1:.N] 
    DT[,idRank:=rank(Index), by = c("id")][idRank == 1, .(id, type)] 
+0

Это действительно работает, и Мне нравится использование 'rank' - проголосовал за другой ответ, поскольку для этого требовался только один дополнительный столбец. Спасибо за ваш вклад, Ханнес, я ценю различные доступные подходы – daRknight

Смежные вопросы