Как найти NA в группах и создать новый столбец для фрейма данных

У меня есть фрейм данных, состоящий из столбца «ID» и столбца «Diff». Столбец ID отвечает за маркировку групп соответствующих значений Diff. Пример выглядит так:

structure(list(ID = c(566, 566, 789, 789, 789, 487, 487, 11, 
11, 189, 189), Diff = c(100, 277, 529, 43, NA, 860, 780, 445, 
NA, 578, 810)), .Names = c("ID", "Diff"), row.names = c(9L, 10L, 
20L, 21L, 22L, 25L, 26L, 51L, 52L, 62L, 63L), class = "data.frame")

Моя цель - найти в каждой группе NA в столбце Diff и создать новый столбец, который имеет значение «True» или «False» для каждой строки, в зависимости от того, имеет ли соответствующая группа NA в Diff.

Я попытался

x <- aggregate(Diff ~ ID, data, is.na)

и

y <- aggregate(Diff ~ ID, data, function(x) any(is.na(x)))

Идея заключалась в том, чтобы слить результат в зависимости от ID. Однако ничего из вышеперечисленного не дало полезного результата. Я знаю, что R может это сделать … и после долгих поисков я спрашиваю вас, как :)


person fr3d-5    schedule 14.01.2014    source источник


Ответы (3)


(У вас уже есть две жизнеспособные стратегии, но вот еще одна, которой концептуально будет проще следовать, если вы относительно новичок в R и не знакомы с тем, как работает plyr.)

Мне часто нужно знать, сколько у меня NA в разных переменных, поэтому вот удобная функция, которую я использую стандартно:

sna <- function(x){
  sum(is.na(x))
}

Оттуда я иногда использую aggregate(), но иногда нахожу ?summaryBy в пакете doBy, чтобы было удобнее. Вот пример:

library(doBy)
z <- summaryBy(Diff~ID, data=my.data, FUN=sna)
z
   ID Diff.sna
1  11        1
2 189        0
3 487        0
4 566        0
5 789        1

После этого вам просто нужно использовать ?merge и преобразуйте количество NAs в логическое, чтобы получить окончательный фрейм данных:

my.data          <- merge(my.data, z, by="ID")
my.data$Diff.sna <- my.data$Diff.sna>0
my.data
    ID Diff Diff.sna
1   11  445     TRUE
2   11   NA     TRUE
3  189  578    FALSE
4  189  810    FALSE
5  487  860    FALSE
6  487  780    FALSE
7  566  100    FALSE
8  566  277    FALSE
9  789  529     TRUE
10 789   43     TRUE
11 789   NA     TRUE
person gung - Reinstate Monica    schedule 14.01.2014
comment
Спасибо. Я предполагаю, что все ответы подходят и приведут к ожидаемым результатам. Однако за этим было проще всего следить, как упоминалось во введении :) - person fr3d-5; 14.01.2014

Вы можете использовать plyr и ddply

require(plyr)
ddply(data, .(ID), transform, na_diff = any(is.na(Diff)))
##     ID Diff na_diff
## 1   11  445    TRUE
## 2   11   NA    TRUE
## 3  189  578   FALSE
## 4  189  810   FALSE
## 5  487  860   FALSE
## 6  487  780   FALSE
## 7  566  100   FALSE
## 8  566  277   FALSE
## 9  789  529    TRUE
## 10 789   43    TRUE
## 11 789   NA    TRUE
person dickoa    schedule 14.01.2014

Очень похожее решение на @dickoa, за исключением base:

do.call(rbind,by(data,data$ID,function(x)transform(x,na_diff=any(is.na(Diff)))))
#         ID Diff na_diff
# 11.51   11  445    TRUE
# 11.52   11   NA    TRUE
# 189.62 189  578   FALSE
# 189.63 189  810   FALSE
# 487.25 487  860   FALSE
# 487.26 487  780   FALSE
# 566.9  566  100   FALSE
# 566.10 566  277   FALSE
# 789.20 789  529    TRUE
# 789.21 789   43    TRUE
# 789.22 789   NA    TRUE

Точно так же вы можете избежать transform с помощью:

data$na_diff<-with(data,by(Diff,ID,function(x) any(is.na(x)))[as.character(ID)])
person nograpes    schedule 14.01.2014
comment
Ницца. Вы можете упростить свой код следующим образом do.call(rbind, by(data, data$ID, transform, na_diff = any(is.na(Diff)))) - person dickoa; 14.01.2014