ifelse over each element of a vector

2020-05-08 08:23发布

Looking at this post, I thought ifelse is vectorized in the sense that f(c(x1, x2, x3)) = c(f(x1), f(x2), f(x3)).

So, I thought if the code for z1 (provided below) will perform the following for each element of the vector y:

  • Test whether it is unity or not.
    • If YES, draw a random number from {1, 3, 5, 7, 9}.
    • If NO, draw a random number from {0, 2, 4, 6, 8}.

But, unfortunately it doesn't do that. It generates once for each case, and returns that very random number always.

Where exactly am I doing wrong? Or, is it actually the expected behaviour of ifelse?

Just to note, if I use this as a wrapper function inside sapply, I get the expected output z2 (in the sense that it is not deterministic as z1 where observing one occurrence of each case is enough), as you can see below.

y <- rbinom(n = 20,
            size = 1,
            prob = 0.5)

z1 <- ifelse(test = (y == 1),
             yes = sample(x = c(1, 3, 5, 7, 9),
                          size = 1),
             no = sample(x = c(0, 2, 4, 6, 8),
                         size = 1))

z2 <- sapply(X = y,
             FUN = function(w)
             {
               ifelse(test = (w == 1),
                      yes = sample(x = c(1, 3, 5, 7, 9),
                                   size = 1),
                      no = sample(x = c(0, 2, 4, 6, 8),
                                  size = 1))
             })

data.frame(y, z1, z2)
#>    y z1 z2
#> 1  0  2  2
#> 2  1  1  3
#> 3  1  1  9
#> 4  1  1  7
#> 5  0  2  0
#> 6  0  2  2
#> 7  1  1  7
#> 8  1  1  7
#> 9  0  2  0
#> 10 1  1  5
#> 11 0  2  0
#> 12 0  2  0
#> 13 0  2  6
#> 14 0  2  0
#> 15 0  2  2
#> 16 1  1  7
#> 17 1  1  7
#> 18 0  2  2
#> 19 0  2  2
#> 20 0  2  0

unique(x = z1[y == 1])
#> [1] 1

unique(x = z1[y == 0])
#> [1] 2

Created on 2019-03-13 by the reprex package (v0.2.1)

Any help will be appreciated.

1条回答
▲ chillily
2楼-- · 2020-05-08 09:09

ifelse isn't a function of one vector, it is a function of 3 vectors of the same length. The first vector, called test, is a boolean, the second vector yes and third vector no give the elements in the result, chosen item-by-item based on the test value.

A sample of size = 1 is a different size than test (unless the length of test is 1), so it will be recycled by ifelse (see note below). Instead, draw samples of the same size as test from the start:

ifelse(
   test = (y == 1),
   yes = sample(x = c(1, 3, 5, 7, 9), size = length(y), replace = TRUE),
   no = sample(x = c(0, 2, 4, 6, 8), size = lenght(y), replace = TRUE)
)

The vectors don't actually have to be of the same length. The help page ?ifelse explains: "If yes or no are too short, their elements are recycled." This is the behavior you observed with "It generates once for each case, and returns that very random number always.".

查看更多
登录 后发表回答