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)
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ątkiemfather
imother
. -
all_vars(is.na(.))
: zachowaj wiersze, gdzieis.na
jestTRUE
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
.
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)
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,]
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
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