Reputation: 1904
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
Upvotes: 1
Views: 4654
Reputation: 206197
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))
Upvotes: 7