Połącz mutate z wartościami warunkowymi

W dużej ramce danych ("myfile") z czterema kolumnami muszę dodać piątą kolumnę z wartościami conditonalnie na podstawie pierwszych czterech kolumn. Ostatnio stałem się wielkim fanem dplyr, głównie ze względu na jego szybkość w dużych zestawach danych. Więc zastanawiałem się, czy mogę poradzić sobie z moim problemem za pomocą funkcji mutate.

Mój dataframe (właściwie jego krótsza wersja) wygląda trochę tak:

  V1 V2 V3 V4
1  1  2  3  5
2  2  4  4  1
3  1  4  1  1
4  4  5  1  3
5  5  5  5  4

Wartości piątej kolumny (V5) opierają się na pewnych warunkowych Zasady:

if (V1==1 & V2!=4){
V5 <- 1
}
else if (V2==4 & V3!=1){
V5 <- 2
}
else {
V5 <- 0
}

Teraz chcę użyć funkcji mutate, aby używać tych reguł we wszystkich wierszach (więc nie muszę używać wolnej pętli). Coś takiego (i tak, Wiem, że to nie działa w ten sposób!):

myfile <- mutate(myfile, if (V1==1 & V2!=4){V5 = 1}
    else if (V2==4 & V3!=1){V5 = 2}
    else {V5 = 0})

To powinien być wynik:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

Jak to zrobić w dplyr?

 54
Author: zx8754, 2014-03-12

3 answers

Spróbuj tego:

myfile %>% mutate(V5 = (V1 == 1 & V2 != 4) + 2 * (V2 == 4 & V3 != 1))

Dając:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

Lub to:

myfile %>% mutate(V5 = ifelse(V1 == 1 & V2 != 4, 1, ifelse(V2 == 4 & V3 != 1, 2, 0)))

Dając:

  V1 V2 V3 V4 V5
1  1  2  3  5  1
2  2  4  4  1  2
3  1  4  1  1  0
4  4  5  1  3  0
5  5  5  5  4  0

Zaproponuj lepszą nazwę dla ramki danych. myfile sprawia, że wydaje się, że zawiera nazwę pliku.

Powyżej użyto tego wejścia:

myfile <- 
structure(list(V1 = c(1L, 2L, 1L, 4L, 5L), V2 = c(2L, 4L, 4L, 
5L, 5L), V3 = c(3L, 4L, 1L, 1L, 5L), V4 = c(5L, 1L, 1L, 3L, 4L
)), .Names = c("V1", "V2", "V3", "V4"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5"))

Update 1 od momentu zamieszczenia dplyr zmienił %.% na %>% więc odpowiednio zmodyfikowaliśmy odpowiedź.

Update 2 dplyr ma teraz case_when, które zapewnia inne rozwiązanie:

myfile %>% 
       mutate(V5 = case_when(V1 == 1 & V2 != 4 ~ 1, 
                             V2 == 4 & V3 != 1 ~ 2,
                             TRUE ~ 0))
 62
Author: G. Grothendieck,
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-11-29 04:07:21

Z dplyr 0.7.2 możesz użyć bardzo przydatnej funkcji case_when:

x=read.table(
 text="V1 V2 V3 V4
 1  1  2  3  5
 2  2  4  4  1
 3  1  4  1  1
 4  4  5  1  3
 5  5  5  5  4")
x$V5 = case_when(x$V1==1 & x$V2!=4 ~ 1,
                 x$V2==4 & x$V3!=1 ~ 2,
                 TRUE ~ 0)

Należy pamiętać, że NA nie są traktowane specjalnie, ponieważ może to wprowadzać w błąd. Funkcja zwróci NA tylko wtedy, gdy nie zostanie spełniony żaden warunek. Jeśli umieścisz linię z TRUE ~ ..., tak jak w moim przykładzie, wartość zwracana nigdy nie będzie NA.

Musisz wyraźnie powiedzieć case_when, aby umieścić NA gdzie należy, dodając wypowiedź w stylu is.na(x$V1) | is.na(x$V3) ~ NA_integer_. Podpowiedź: funkcja dplyr::coalesce() może być tutaj naprawdę przydatna czasami!

Ponadto, NA sam zwykle nie zadziała, musisz umieścić specjalne NA wartości : NA_integer_, NA_character_ lub NA_real_.

 13
Author: Dan Chaltiel,
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-09-30 05:04:25

Wygląda na to, że derivedFactor z pakietu mosaic został do tego zaprojektowany. W tym przykładzie wyglądałoby to mniej więcej tak:

library(mosaic)
myfile <- mutate(myfile, V5 = derivedFactor(
    "1" = (V1==1 & V2!=4),
    "2" = (V2==4 & V3!=1),
    .method = "first",
    .default = 0
    ))

(jeśli chcesz, aby wynik był liczbowy zamiast współczynnika, owiń derivedFactor znakiem as.numeric.)

Zauważ, że opcja .default w połączeniu z .method = "first" ustawia warunek "else" -- takie podejście jest opisane w pliku pomocy dla derivedFactor.

 10
Author: Jake Fisher,
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
2015-10-22 20:14:44