Reputation: 72838
Why won't these ifelse()
s don't throw data frames (or matrices)?
x <- data.frame(a=1000, b=100)
> x
a b
1 1000 100
> ifelse(x[, 2] >= 8, x, NA)
[[1]]
[1] 1000
> ifelse(x[, 2] >= 8, x[1:2], NA)
[[1]]
[1] 1000
> ifelse(x[, 2] >= 8, cbind(x[[1]], x[[2]]), NA)
[1] 1000
The second column is always missing. How to get this right?
Upvotes: 1
Views: 56
Reputation: 20095
Below quoted lines about return value from ifelse
are very important (taken from help
) in order to understand behavior of ifelse
Value
A vector of the same length and attributes (including dimensions and "class") as test and data values from the values of yes or no.
Details
If yes or no are too short, their elements are recycled.
In summary it suggests that for each row
and column
in test section of the corresponding data values will be returned for yes and no.
Lets take few examples to understand it.
x <- data.frame(a=1000, b=100) ifelse(x[, 2] >= 8, x, NA) # Test : 1 row and 1 col. Hence return is x[1] # [[1]] #[1] 1000 ifelse(x[, 2] >= 8, x[,2], NA) # Test : 1 row and 1 col. Hence return is x[,2][1] #[1] 100 ifelse(x >= 8, x, NA) # Test : 1 row and 2 cols. Hence return is x[1,1] and x[1,1] # [[1]] # [1] 1000 # # [[2]] # [1] 100 ifelse(x >= 8, 4, NA) # Test : 1 row and 2 cols. Values are recycled. 4 & 4 for corresponding row/col # a b #[1,] 4 4 #Change x to 2x2 x <- data.frame(a=1000:1001, b=100:101) ifelse(x >= 8, 4, NA) # Test : 2 row and 2 cols. Result will be 2 x 2 # a b #[1,] 4 4 #[2,] 4 4
Now, what option does one have to handle such problem?
Certainly one can use if
as suggested by @Jordi. But just be careful that if
is not vectorised. Hence test condition is applied only on 1st
element when vector
is used in test condition. To handle those situations, functions like any
or all
comes very handy and make it possible to to use vector
as part of test condition in if
.
Upvotes: 3
Reputation: 1343
From its help file:
ifelse returns a value with the same shape as test which is filled with elements selected from either yes or no depending on whether the element of test is TRUE or FALSE.
So it does actually return a dataframe if the input is a dataframe:
ifelse(x[, 1, drop = FALSE] > 0, 10, NA)
But in your case it is easier to use
if (test) x else NA
Upvotes: 4