web-dev-qa-db-fra.com

filtre dplyr avec condition sur plusieurs colonnes

Voici des données factices:

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

Je veux filtrer cette ligne:

  father  mother  children cousins
    1      1       NA      NA

Je peux le faire avec:

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

Ma question: j'ai plusieurs colonnes comme grand-père, oncle1, oncle2, uncle3 et je veux éviter quelque chose comme ça:

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

Comment puis-je utiliser dplyr pour dire filtrer toute la colonne avec na (sauf père == 1 & mère == 1)

13
Wilcar

Une solution dplyr (version> = 0.5.0.9004) possible est:

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

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

Explication:

  • vars(-father, -mother): sélectionnez toutes les colonnes sauf father et mother.
  • all_vars(is.na(.)): conserve les lignes où is.na est TRUE pour tous les colonnes sélectionnées.

note: any_vars doit être utilisé à la place de all_vars si les lignes où is.na est TRUE pour toute colonne doivent être conservées.

21
mt1022

Une solution dplyr:

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

Où '2' est le nombre de colonnes qui doivent être NA.

Cela donne:

> test
  father mother children cousins
1      1      1       NA      NA

Vous pouvez également appliquer cette logique dans la base R:

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

Aucune des réponses ne semble être une solution adaptable. Je pense que l'intention n'est pas de lister toutes les variables et valeurs pour filtrer les données.

Un moyen simple d'y parvenir consiste à fusionner. Si vous avez toutes les conditions dans df_filter, vous pouvez le faire:

df_results = df_filter %>% left_join(df_all)
4
Jfly

Voici une méthode de base R utilisant deux fonctions Reduce et [ au sous-ensemble.

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

Chaque Reduce prend consécutivement les variables fournies et effectue une vérification logique. Les deux résultats sont liés à un &. Le deuxième argument des fonctions Reduce peut être ajusté pour inclure toutes les variables que vous souhaitez dans le data.frame.

Ensuite, utilisez le vecteur logique pour sous-ensemble

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