round2 <- function(x, y) {
if(is.na(x)) { return ('') }
return(paste0(round(100 * x, 0), '% ', round(100 * y, 0), '%'))
}
mydf <- data.frame(a = c(NA, .323, .555), b = c(NA, .232, .541))
mydf %>% dplyr::mutate(c = round2(a, b))
The main part of the function paste0(round(...))
works just fine, however the if(is.na(x)) { return ('') }
does not properly handle that x and y are vectors. As a result, the entire column c
in mydf
is an empty string. How can we update this so only the first row in mydf
returns an empty string?
CodePudding user response:
if/else
are not vectorized - expect a single TRUE/FALSE
it can work if we use rowwise
as grouping
library(dplyr)
mydf %>%
rowwise %>%
dplyr::mutate(c = round2(a, b)) %>%
ungroup
-output
# A tibble: 3 × 3
a b c
<dbl> <dbl> <chr>
1 NA NA ""
2 0.323 0.232 "32% 23%"
3 0.555 0.541 "56% 54%"
as grouping or Vectorize
the function
mydf %>%
dplyr::mutate(c = Vectorize(round2)(a, b))
If we want to create a vectorized function, make use of ifelse/case_when
etc which are already vectorized
round2new <- function(x, y) {
case_when(is.na(x) ~ "",
TRUE ~ paste0(round(100 * x, 0), '% ', round(100 * y, 0), '%'))
}
mydf %>%
dplyr::mutate(c = round2new(a, b))
a b c
1 NA NA
2 0.323 0.232 32% 23%
3 0.555 0.541 56% 54%
NOTE: Calling Vectorize
or using rowwise
grouping is iterating over each row and will be slower than making use of vectorized functions (ifelse/case_when/if_else
) while constructing the function
CodePudding user response:
the if () function if you pass a vector, it will only take the first value of vector.. also a warning will be displayed on console..
better you pass the vector in function call and use the for call up to length of vector and check each x[j] j=1:length(x)
or you can use
vec [1] 2 3 NA sum(is.na(vec)) [1] 1
something like this in your logic building..