filtr dplyr z warunkiem na wielu kolumnach

Oto atrapa danych:

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

Chcę filtrować ten wiersz:

  father  mother  children cousins
    1      1       NA      NA

Mogę to zrobić z:

test <- dataset %>% 
filter(father==1 & mother==1) %>%
filter (is.na(children)) %>%
filter (is.na(cousins))
test  
Moje pytanie : Mam wiele felietonów typu dziadek, wujek1, wujek2, wujek3 i chcę uniknąć czegoś takiego:
  filter (is.na(children)) %>%
  filter (is.na(cousins)) %>%
  filter (is.na(uncle1)) %>%
  filter (is.na(uncle2)) %>%
  filter (is.na(uncle3)) 
  and so on...

Jak mogę użyć dplyr, aby powiedzieć filtruj całą kolumnę za pomocą na (z wyjątkiem ojca==1 & matki==1)

 21
Author: Wilcar, 2017-05-12

4 answers

Możliwe rozwiązanie dplyr (0.5.0.9004

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

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

Wyjaśnienie:

  • vars(-father, -mother): Zaznacz wszystkie kolumny z wyjątkiem father i mother.
  • all_vars(is.na(.)): zachowaj wiersze, gdzie is.na jest TRUE dla wszystkich wybranych kolumn.

Uwaga: any_vars powinny być używane zamiast all_vars, jeśli wiersze, w których is.na jest TRUE dla należy zachować dowolną kolumnę.


Aktualizacja (2020-11-28)

Od _at funkcji i vars zostały zastąpione przez użycie across od dplyr 1.0, teraz zaleca się następujący sposób (lub podobny):

dataset %>%
    filter(across(c(father, mother), ~ !is.na(.x))) %>%
    filter(across(c(-father, -mother), is.na))

Zobacz więcej przykład across i jak przepisać poprzedni kod z nowym podejściem tutaj: operaty colomn-wise lub wpisz vignette("colwise") W R Po zainstalowaniu najnowszej wersji dplyr.

 41
Author: mt1022,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-28 15:29:03

Żadna z odpowiedzi nie wydaje się być elastycznym rozwiązaniem. Myślę, że intencją nie jest lista wszystkich zmiennych i wartości do filtrowania danych.

Jednym z łatwych sposobów na osiągnięcie tego celu jest połączenie. Jeśli masz wszystkie warunki w df_filter, możesz to zrobić:

df_results = df_filter %>% left_join(df_all)
 6
Author: Feng Jiang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-05 01:28:42

A dplyr rozwiązanie:

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

Gdzie " 2 " to liczba kolumn, które powinny być NA.

Daje to:

> test
  father mother children cousins
1      1      1       NA      NA

Możesz zastosować tę logikę również w bazie R:

dataset[dataset$father==1 & dataset$mother==1 & rowSums(is.na(dataset[,3:4]))==2,]
 5
Author: Jaap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-12 13:49:18

Oto podstawowa metoda R wykorzystująca dwie funkcje Reduce i [ do podzbioru.

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

Każda Reduce kolejno pobiera podane zmienne i wykonuje logiczne sprawdzenie. Oba wyniki są połączone &. Drugi argument funkcji Reduce może być dostosowany tak, aby zawierał dowolne zmienne w danych.ramki, które chcesz.

Następnie użyj wektora logicznego do podzbioru

dataset[keepers,]
  father mother children cousins
1      1      1       NA      NA
 3
Author: lmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-12 13:35:23