R ocena warunkowa przy użyciu operatora rury %>%
Przy użyciu operatora rury {[3] } z pakietami takimi jak dplyr
, ggvis
, dycharts
, itd, jak zrobić krok warunkowo? Na przykład;
step_1 %>%
step_2 %>%
if(condition)
step_3
Te podejścia nie wydają się działać:
step_1 %>%
step_2
if(condition) %>% step_3
step_1 %>%
step_2 %>%
if(condition) step_3
Jest długa droga:
if(condition)
{
step_1 %>%
step_2
}else{
step_1 %>%
step_2 %>%
step_3
}
Czy jest lepszy sposób bez całej nadmiarowości?
5 answers
Oto szybki przykład, który wykorzystuje .
i ifelse
:
X<-1
Y<-T
X %>% add(1) %>% { ifelse(Y ,add(1), . ) }
In the ifelse
, if Y
is TRUE
if will add 1, otherwise it will just return the last value of X
. {[2] } jest stand-in, który mówi funkcji, gdzie wyjście z poprzedniego kroku łańcucha idzie, więc mogę go użyć na obu gałęziach.
Edit
Jak zauważył @ BenBolker, możesz nie chcieć ifelse
, więc oto wersja if
.
X %>%
add(1) %>%
{if(Y) add(1) else .}
Dzięki @ Frank za wskazując, że powinienem używać {
szelek wokół moich if
i ifelse
wypowiedzi, aby kontynuować łańcuch.
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-31 02:57:37
Myślę, że to przypadek purrr::when
. Podsumujmy kilka liczb, jeśli ich suma jest poniżej 25, w przeciwnym razie zwróć 0.
library("magrittr")
1:3 %>%
purrr::when(sum(.) < 25 ~ sum(.),
~0
)
#> [1] 6
when
Zwraca wartość wynikającą z działania pierwszego poprawnego warunku. Umieść warunek na lewo od ~
, a działanie na prawo od niego. Powyżej użyliśmy tylko jednego warunku (a następnie innego przypadku), ale możesz mieć wiele warunków.
Możesz łatwo zintegrować to z dłuższą rurą.
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-07-09 11:09:54
Wydaje mi się, że najłatwiej byłoby trochę odstąpić od rur (chociaż byłbym zainteresowany innymi rozwiązaniami), np.:
library("dplyr")
z <- data.frame(a=1:2)
z %>% mutate(b=a^2) -> z2
if (z2$b[1]>1) {
z2 %>% mutate(b=b^2) -> z2
}
z2 %>% mutate(b=b^2) -> z3
Jest to niewielka modyfikacja odpowiedzi @ JohnPaul (możesz nie
really want ifelse
, który ocenia oba argumenty
i jest wektoryzowany). Byłoby miło zmodyfikować to, aby powrócić
.
automatycznie, jeśli warunek jest fałszywy ...
(Uwaga : myślę, że to działa, ale tak naprawdę nie przetestowałem/nie pomyślałem
o tym za dużo ...)
iff <- function(cond,x,y) {
if(cond) return(x) else return(y)
}
z %>% mutate(b=a^2) %>%
iff(cond=z2$b[1]>1,mutate(.,b=b^2),.) %>%
mutate(b=b^2) -> z4
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-06-02 19:02:55
Oto wariacja na temat odpowiedzi udzielonej przez @ JohnPaul. Zmienna ta używa funkcji `if`
zamiast wyrażenia złożonego if ... else ...
.
library(magrittr)
X <- 1
Y <- TRUE
X %>% `if`(Y, . + 1, .) %>% multiply_by(2)
# [1] 4
Zauważ, że w tym przypadku nawiasy klamrowe nie są potrzebne wokół funkcji `if`
, ani wokół funkcji ifelse
-tylko wokół instrukcji if ... else ...
. Jeśli jednak symbol zastępczy kropki pojawia się tylko w zagnieżdżonym wywołaniu funkcji, to magrittr domyślnie połączy lewą stronę z pierwszym argumentem prawej strony. To zachowanie jest nadpisywane przez zamknięcie wyrażenia w nawiasach klamrowych. Zauważ różnicę między tymi dwoma łańcuchami:
X %>% `if`(Y, . + 1, . + 2)
# [1] TRUE
X %>% {`if`(Y, . + 1, . + 2)}
# [1] 4
Symbol zastępczy kropki jest zagnieżdżany w wywołaniu funkcji za każdym razem, gdy pojawia się w funkcji `if`
, ponieważ . + 1
i . + 2
są interpretowane odpowiednio jako `+`(., 1)
i `+`(., 2)
. Tak więc, pierwsze wyrażenie zwraca wynik `if`(1, TRUE, 1 + 1, 1 + 2)
, (co dziwne, {[2] }nie skarży się na dodatkowe nieużywane argumenty), a drugie wyrażenie zwraca wynik `if`(TRUE, 1 + 1, 1 + 2)
, co jest pożądanym zachowaniem w tym przypadku.
Aby uzyskać więcej informacji o tym, jak operator Rury magrittr traktuje symbol zastępczy kropki, zobacz plik pomocy dla %>%
, w szczególności sekcję "używanie kropki do celów drugorzędnych".
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-07-09 05:14:19
Podoba mi się purrr::when
i inne rozwiązania bazowe tutaj są świetne, ale chciałem czegoś bardziej kompaktowego i elastycznego, więc zaprojektowałem function pif
(pipe if), patrz kod i doc na końcu odpowiedzi.
Argumenty mogą być wyrażeniami funkcji (wspierana jest notacja formuł), a dane wejściowe są zwracane domyślnie bez zmian, jeśli warunek to FALSE
.
Użyte na przykładach z innych odpowiedzi:
## from Ben Bolker
data.frame(a=1:2) %>%
mutate(b=a^2) %>%
pif(~b[1]>1, ~mutate(.,b=b^2)) %>%
mutate(b=b^2)
# a b
# 1 1 1
# 2 2 16
## from Lorenz Walthert
1:3 %>% pif(sum(.) < 25,sum,0)
# [1] 6
## from clbieganek
1 %>% pif(TRUE,~. + 1) %>% `*`(2)
# [1] 4
# from theforestecologist
1 %>% `+`(1) %>% pif(TRUE ,~ .+1)
# [1] 3
Inne przykłady :
## using functions
iris %>% pif(is.data.frame, dim, nrow)
# [1] 150 5
## using formulas
iris %>% pif(~is.numeric(Species),
~"numeric :)",
~paste(class(Species)[1],":("))
# [1] "factor :("
## using expressions
iris %>% pif(nrow(.) > 2, head(.,2))
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa
# 2 4.9 3.0 1.4 0.2 setosa
## careful with expressions
iris %>% pif(TRUE, dim, warning("this will be evaluated"))
# [1] 150 5
# Warning message:
# In inherits(false, "formula") : this will be evaluated
iris %>% pif(TRUE, dim, ~warning("this won't be evaluated"))
# [1] 150 5
Function
#' Pipe friendly conditional operation
#'
#' Apply a transformation on the data only if a condition is met,
#' by default if condition is not met the input is returned unchanged.
#'
#' The use of formula or functions is recommended over the use of expressions
#' for the following reasons :
#'
#' \itemize{
#' \item If \code{true} and/or \code{false} are provided as expressions they
#' will be evaluated wether the condition is \code{TRUE} or \code{FALSE}.
#' Functions or formulas on the other hand will be applied on the data only if
#' the relevant condition is met
#' \item Formulas support calling directly a column of the data by its name
#' without \code{x$foo} notation.
#' \item Dot notation will work in expressions only if `pif` is used in a pipe
#' chain
#' }
#'
#' @param x An object
#' @param p A predicate function, a formula describing such a predicate function, or an expression.
#' @param true,false Functions to apply to the data, formulas describing such functions, or expressions.
#'
#' @return The output of \code{true} or \code{false}, either as expressions or applied on data as functions
#' @export
#'
#' @examples
#'# using functions
#'pif(iris, is.data.frame, dim, nrow)
#'# using formulas
#'pif(iris, ~is.numeric(Species), ~"numeric :)",~paste(class(Species)[1],":("))
#'# using expressions
#'pif(iris, nrow(iris) > 2, head(iris,2))
#'# careful with expressions
#'pif(iris, TRUE, dim, warning("this will be evaluated"))
#'pif(iris, TRUE, dim, ~warning("this won't be evaluated"))
pif <- function(x, p, true, false = identity){
if(!requireNamespace("purrr"))
stop("Package 'purrr' needs to be installed to use function 'pif'")
if(inherits(p, "formula"))
p <- purrr::as_mapper(
if(!is.list(x)) p else update(p,~with(...,.)))
if(inherits(true, "formula"))
true <- purrr::as_mapper(
if(!is.list(x)) true else update(true,~with(...,.)))
if(inherits(false, "formula"))
false <- purrr::as_mapper(
if(!is.list(x)) false else update(false,~with(...,.)))
if ( (is.function(p) && p(x)) || (!is.function(p) && p)){
if(is.function(true)) true(x) else true
} else {
if(is.function(false)) false(x) else false
}
}
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-05 09:33:03