Фильтр dplyr с условием на нескольких столбцах

Вот фиктивные данные:

father<- c(1, 1, 1, 1, 1)
mother<- c(1, 1, 1, NA, NA) 
children <- c(NA, NA, 2, 5, 2) 
cousins   <- c(NA, 5, 1, 1, 4) 


dataset <- data.frame(father, mother, children, cousins)  
dataset


father  mother  children cousins
1      1       NA      NA
1      1       NA       5
1      1        2       1
1     NA        5       1
1     NA        2       4

Я хочу отфильтровать эту строку:

  father  mother  children cousins
    1      1       NA      NA

Я могу сделать это с помощью:

test <- dataset %>% 
filter(father==1 & mother==1) %>%
filter (is.na(children)) %>%
filter (is.na(cousins))
test  

Мой вопрос: у меня много столбцов, таких как великий отец, дядя1, дядя2, дядя3, и я хочу избежать чего-то подобного:

  filter (is.na(children)) %>%
  filter (is.na(cousins)) %>%
  filter (is.na(uncle1)) %>%
  filter (is.na(uncle2)) %>%
  filter (is.na(uncle3)) 
  and so on...

Как я могу использовать dplyr, чтобы сказать, фильтровать весь столбец с na (кроме отца == 1 и mother == 1)

Ответ 1

Возможное решение dplyr (версия> = 0.5.0.9004):

# > packageVersion('dplyr')
# [1] ‘0.5.0.9004

dataset %>%
    filter(!is.na(father), !is.na(father)) %>%
    filter_at(vars(-father, -mother), all_vars(is.na(.)))

Объяснение:

  • vars(-father, -mother): выберите все столбцы, кроме father и mother.
  • all_vars(is.na(.)): хранить строки, где is.na равно TRUE для всех выбранных столбцов.

примечание: следует использовать any_vars вместо all_vars, если нужно сохранить строки, где is.na равен TRUE для любого столбца.

Ответ 2

Решение dplyr:

test <- dataset %>% 
  filter(father==1 & mother==1 & rowSums(is.na(.[,3:4]))==2)

Где "2" - количество столбцов, которые должны быть NA.

Это дает:

> test
  father mother children cousins
1      1      1       NA      NA

Вы можете применить эту логику и в базе R:

dataset[dataset$father==1 & dataset$mother==1 & rowSums(is.na(dataset[,3:4]))==2,]

Ответ 3

Ни один из ответов не является адаптивным решением. Я думаю, что намерение состоит не в перечислении всех переменных и значений для фильтрации данных.

Один простой способ добиться этого - слияние. Если у вас есть все условия в df_filter, вы можете сделать это:

df_results = df_filter %>% left_join(df_all)

Ответ 4

Вот базовый метод R, использующий две функции Reduce и [ к подмножеству.

keepers <- Reduce(function(x, y) x == 1 & y == 1, dataset[, 1:2]) &
           Reduce(function(x, y) is.na(x) & is.na(y), dataset[, 3:4])
keepers
[1]  TRUE FALSE FALSE FALSE FALSE

Каждое Reduce последовательно принимает предоставленные переменные и выполняет логическую проверку. Два результата связаны с &. Второй аргумент функции " Reduce можно настроить так, чтобы он включал любые переменные в формате data.frame, который вы хотите.

Затем используйте логический вектор для подмножества

dataset[keepers,]
  father mother children cousins
1      1      1       NA      NA