简体   繁体   中英

dplyr mutate_at and ifelse() is not vectorised

I am attempting to use mutate_at at a subset of columns in my data frame. However, when the function I use is ifelse , it does not appear to be vectorizing.

For example, the code below should give the same output as the original input.

set.seed(1)
stack_names <- c('a','c','d','e')
stack_df <- data.frame(a = 1:10, b = 11:20, c = 21:30, d = rep(1, 10), e = rnorm(10))

#     a  b  c d          e
# 1   1 11 21 1 -0.6264538
# 2   2 12 22 1  0.1836433
# 3   3 13 23 1 -0.8356286
# 4   4 14 24 1  1.5952808
# 5   5 15 25 1  0.3295078
# 6   6 16 26 1 -0.8204684
# 7   7 17 27 1  0.4874291
# 8   8 18 28 1  0.7383247
# 9   9 19 29 1  0.5757814
# 10 10 20 30 1 -0.3053884

stack_df %>% mutate_at(.vars = vars(one_of(stack_names)), 
                         funs(ifelse(length(unique(.)) == 1, ., .)))
#    a  b  c d          e
# 1  1 11 21 1 -0.6264538
# 2  1 12 21 1 -0.6264538
# 3  1 13 21 1 -0.6264538
# 4  1 14 21 1 -0.6264538
# 5  1 15 21 1 -0.6264538
# 6  1 16 21 1 -0.6264538
# 7  1 17 21 1 -0.6264538
# 8  1 18 21 1 -0.6264538
# 9  1 19 21 1 -0.6264538
# 10 1 20 21 1 -0.6264538

Is this a known behavior with ifelse ? When I try a similar code but use a different function, it works fine.

stack_df %>% mutate_at(.vars = vars(one_of(stack_names)), 
                           funs(. + mean(.)))
#       a  b    c d          e
# 1   6.5 11 46.5 2 -0.4942510
# 2   7.5 12 47.5 2  0.3158461
# 3   8.5 13 48.5 2 -0.7034258
# 4   9.5 14 49.5 2  1.7274836
# 5  10.5 15 50.5 2  0.4617106
# 6  11.5 16 51.5 2 -0.6882656
# 7  12.5 17 52.5 2  0.6196318
# 8  13.5 18 53.5 2  0.8705275
# 9  14.5 19 54.5 2  0.7079841
# 10 15.5 20 55.5 2 -0.1731856

Your first parameter to ifelse is a logical vector of length 1. You're only going to get one value that way. See

ifelse(TRUE, 5:1, 1:5)
# [1] 5    # one 1 value returned, not 5

And when you test length(unique(.)) == 1 are are only going to get one TRUE or FALSE depending on whether or not all the values in the column are the same.

All the parameters to ifelse should be the same length. It's unclear what you are really trying to do here so it's not obvious what the solution might be. Seems like you might just want to conditionally perform the mutate or use a mutate_if or some sort. Of maybe you just want a regular if statement.

myfun <- function(x) {
    if (length(unique(x)) == 1) x else x
}
stack_df %>% mutate_at(.vars = vars(one_of(stack_names)), funs(myfun))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM