Как удалить строку, содержащую NA, если NA допускаются до того, как человек входит в образец? - PullRequest
1 голос
/ 20 марта 2019

Я работаю с панельным набором данных, содержащим годы 1-12.Если человек входит в год 4, его значения для Weight будут равны NA до года 4. Я хочу удалить эту строку (человек), только если после года 4 есть какие-либо значения NA.

data : Weight_Y1   W_Y2    W_Y3    W_Y4    W_Y5    W_Y6    W_Y7    W_8     W_9 ...
Ind_1    NA        NA       NA     82kg   81       83      84      NA      86

Это лицо должно быть удалено.Таким образом, как только наблюдение регистрируется как активное в опросе, NA не допускается для следующих наблюдений.Помимо Weight у меня также есть другие переменные (столбцы), поэтому мне нужно сделать это и для определенных столбцов.

Ответы [ 3 ]

1 голос
/ 20 марта 2019

Опция с apply с использованием MARGIN = 1 по строкам

#Select columns based on pattern in the weight column
cols <- grep("^W", names(df))

#Select rows only if there is no NA after the first non-NA is encountered.
df[!apply(df[cols], 1, function(x) any(which(is.na(x)) > which.max(!is.na(x)))), ]

#   data W_Y1 W_Y2 W_Y3 W_Y4 W_Y5 W_Y6 W_Y7 W_8 W_9
#2 Ind_2   NA   NA   NA   82   81   83   84  65  86

Использование аналогичной логики, но с mapply и max.col

df[mapply(function(x, y) !any(which(is.na(df[x, cols])) > y),1:nrow(df),
       max.col(!is.na(df[cols]), ties.method = "first")), ]

Использованиеmax.col мы находим индекс первого не-NA значения в cols и затем проверяем, есть ли какое-либо значение в этой строке, которое имеет NA после этого индекса.

data

Я добавил несколько строк, чтобы сделать лучший пример

df <- structure(list(data = structure(1:4, .Label = c("Ind_1", "Ind_2", 
"Ind_3", "Ind_4"), class = "factor"), W_Y1 = c(NA, NA, NA, NA
), W_Y2 = c(NA, NA, NA, 23L), W_Y3 = c(NA, NA, NA, NA), W_Y4 = c(82L, 
82L, 82L, 82L), W_Y5 = c(81L, 81L, 81L, 81L), W_Y6 = c(83L, 83L, 
83L, 83L), W_Y7 = c(84L, 84L, NA, 84L), W_8 = c(NA, 65L, NA, 
12L), W_9 = c(86L, 86L, 86L, 86L)), class = "data.frame", row.names = c(NA, 
-4L))

df
#   data W_Y1 W_Y2 W_Y3 W_Y4 W_Y5 W_Y6 W_Y7 W_8 W_9
#1 Ind_1   NA   NA   NA   82   81   83   84  NA  86
#2 Ind_2   NA   NA   NA   82   81   83   84  65  86
#3 Ind_3   NA   NA   NA   82   81   83   NA  NA  86
#4 Ind_4   NA   23   NA   82   81   83   84  12  86
1 голос
/ 20 марта 2019

tidyverse решение:

library(tidyverse)

df %>%
  gather(year, weight, W_Y1:W_Y12) %>%
  group_by(data) %>%
  mutate(
    cond = max(which(is.na(weight))) < min(which(!is.na(weight))),
    year = year %>% reorder(str_extract(year, '\\d+') %>% as.numeric()) # just to keep right order of columns after 'spread()'
  ) %>%
  spread(year, weight) %>%
  filter(cond)
0 голосов
/ 20 марта 2019

Мы можем проверить NA, используя base::rle, а затем отфильтровать, когда NA произошли один или менее

flag<-apply(df[,grepl('^W',names(df))],1, function(x) sum(rle(is.na(x))$values))
df[df$flag<=1,]
...