I would like to vectorize such function:
if (i > 0)
fun1(a[i])
else
fun2(i)
where fun1, fun2 are already vectorized, and a is a vector.
My attempt:
ifelse(i > 0, fun1(a[i]), fun2(i))
However it is wrong!
> a <- c(1,2,3,4,5)
> i<-c(0,1,2,3)
> ifelse(i > 0, a[i], 0)
[1] 0 2 3 1 # expected 0 1 2 3
Do I have to use sapply? Is there any simple alternative that works?
There is nothing wrong. a[i] evaluates to c(1,2,3) since a[0] is ignored. this is recycled to c(1,2,3,1) to match length(i). So you get 0 2 3 1 from your ifelse because the first element of i is FALSE, and the other come from a[i] recycled.
There is a workaroud though: you can replace non-positive indices with NA:
> ifelse(i > 0, a[ifelse(i > 0, i, NA)], 0)
[1] 0 1 2 3
Related
I am trying to solve this problem with the r language. But I didn't get the answer I expected. My code return -5, while the correct return should be -5, 0, 0, 0, 5. I think my code didn't go through everything in the input_vector. How can i fix it?
It doesn't need any loop i.e.
lambda <- 4
ifelse(abs(v1) > lambda, v1, 0)
[1] -5 0 0 0 5
Or simply multiply by the logical vector (TRUE -> 1 and FALSE -> 0)
v1 * (abs(v1) > lambda)
[1] -5 0 0 0 5
But, if the intention is to use for loop, create a output vector to collect the output and return once at the end
sign.function <- function(input_vector) {
out <- numeric(length(input_vector))
for(i in seq_along(input_vector)) {
if(abs(input_vector[i]) > lambda) {
out[i] <- input_vector[i]
}
}
return(out)
}
> sign.function(v1)
[1] -5 0 0 0 5
data
v1 <- c(-5, -3, 0, 3, 5)
I wanted to explain my problem with codes
example_1 <- sample(-100:100, 100) # simple sample for my question
example_1[30] <- NA # changed one of them to NA
not_equal_zero <- matrix(NA, 100, 1) # matrix to find out if there is any zeros (1 for TRUE, 0 for FALSE)
for (i in 1:100) { # check each observation if it is 0 assign 1 to "not equal zero matrix"
if (example_1[i] == 0) {
not_equal_zero[i] <- 1
} else {
not_equal_zero[i] <- 0
}
}
When i = 30 it finds 0, and terminates. I am not checking only against zero. I have special values. What is the solution for this problem?
2 == 0 # it gives FALSE
0 == 0 # it gives TRUE
NA == 0 # it gives NA but i need FALSE
NA gives NA when compared to anything. You probably want to replace:
if (example_1[i] == 0)
with:
if (!is.na(example_1[i]) && example_1[i] == 0)
For time series analysis I handle data that often contains leading and trailing zero elements. In this example, there are 3 zeros at the beginning an 2 at the end. I want to get rid of these elements, and filter for the contents in the middle (that also may contain zeros)
vec <- c(0, 0, 0, 1, 2, 0, 3, 4, 0, 0)
I did this by looping from the beginning and end, and masking out the unwanted elements.
mask <- rep(TRUE, length(vec))
# from begin
i <- 1
while(vec[i] == 0 && i <= length(vec)) {
mask[i] <- FALSE
i <- i+1
}
# from end
i <- length(vec)
while(i >= 1 && vec[i] == 0) {
mask[i] <- FALSE
i <- i-1
}
cleanvec <- vec[mask]
cleanvec
[1] 1 2 0 3 4
This works, but I wonder if there is a more efficient way to do this, avoiding the loops.
vec[ min(which(vec != 0)) : max(which(vec != 0)) ]
Basically the which(vec != 0) part gives the positions of the numbers that are different from 0, and then you take the min and max of them.
We could use the range and Reduce to get the sequence
vec[Reduce(`:`, range(which(vec != 0)))]
#[1] 1 2 0 3 4
Take the cumsum forward and backward of abs(vec) and keep only elements > 0. if it were known that all elements of vec were non-negative, as in the question, then we could optionally omit abs.
vec[cumsum(abs(vec)) > 0 & rev(cumsum(rev(abs(vec)))) > 0]
## [1] 1 2 0 3 4
I have a variable b which is of varying length.
Eg. it can be
b=0 or b=c(1,4,5)
I have an if condition stating that if
b=0 then it should do something.
Whenever b is not 0 or is of length larger than 1 I get the warning:
the condition has length > 1 and only the first element will be used
Basically what I would like to have is: if b=0 then do something otherwise do something else REGARDLESS of the length of the vector.
How should I do this properly?
There is an alternative solution using identical, any and all.
From your description I would deduce three scenarios, not sure which one you'll actually need:
Do something only if b==0. If b!=0 or if length(b)>1 then don't do it.
TRUE only for b <- 0
if (isTRUE(identical(b, 0))) {
# do something
}
Do something if b==0 or if all elements of b are 0.
TRUE for b <- 0 and b <- c(0, 0) and b <- c(0, 0, 0) and ...
if (all(b==0)) {
# do something
}
Do something if b==0 or if any element of b is 0.
TRUE for b <- 0 and b <- c(12, 0, 34, 2, 3) and b <- c(0, 0, 3, 2) and ...
if (any(b==0)) {
# do something
}
Try %in% as in:
foo <- function(b) {
if(0 %in% b) {
## do something
writeLines("Zero was in `b`")
}
}
> b <- 0
> foo(b)
Zero was in `b`
> b <- c(1,4,5)
> foo(b)
> b <- c(b, 0)
> foo(b)
Zero was in `b`
The point here is to check if the thing you are interested in (here 0) is included in the set of items supplied via the vector b.
For the "do something else case you need to extend foo() with an else clause:
foo <- function(b) {
if(0 %in% b) {
## do something
writeLines("Zero was in `b`")
} else {
## do something else
writeLines("Zero was not in `b`")
}
}
> b <- 0
> foo(b)
Zero was in `b`
> b <- c(1,4,5)
> foo(b)
Zero was not in `b`
> b <- c(b, 0)
> foo(b)
Zero was in `b`
I came to R from SAS, where numeric missing is set to infinity. So we can just say:
positiveA = A > 0;
In R, I have to be verbose like:
positiveA <- ifelse(is.na(A),0, ifelse(A > 0, 1, 0))
I find this syntax is hard to read. Is there anyway I can modify ifelse function to consider NA a special value that is always false for all comparison conditions? If not, considering NA as -Inf will work too.
Similarly, setting NA to '' (blank) in ifelse statement for character variables.
Thanks.
This syntax is easier to read:
x <- c(NA, 1, 0, -1)
(x > 0) & (!is.na(x))
# [1] FALSE TRUE FALSE FALSE
(The outer parentheses aren't necessary, but will make the statement easier to read for almost anyone other than the machine.)
Edit:
## If you want 0s and 1s
((x > 0) & (!is.na(x))) * 1
# [1] 0 1 0 0
Finally, you can make the whole thing into a function:
isPos <- function(x) {
(x > 0) & (!is.na(x)) * 1
}
isPos(x)
# [1] 0 1 0 0
Replacing a NA value with zero seems rather strange behaviour to expect. R considers NA values missing (although hidden far behind scenes where you (never) need to go they are negative very large numbers when numeric ))
All you need to do is A>0 or as.numeric(A>0) if you want 0,1 not TRUE , FALSE
# some dummy data
A <- seq(-1,1,l=11)
# add NA value as second value
A[2] <- NA
positiveA <- A>0
positiveA
[1] FALSE NA FALSE FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE
as.numeric(positiveA) #
[1] 0 NA 0 0 0 0 1 1 1 1 1
note that
ifelse(A>0, 1,0) would also work.
The NA values are "retained", or dealt with appropriately. R is sensible here.
Try this:
positiveA <- ifelse(!is.na(A) & A > 0, 1, 0)
If you are working with integers you can use %in%
For example, if your numbers can go up to 2
test <- c(NA, 2, 1, 0, -1)
other people has suggested to use
(test > 0) & (!is.na(test))
or
ifelse(!is.na(test) & test > 0, 1, 0)
my solution is simpler and gives you the same result.
test %in% 1:2
YOu can use the missing argument i if_else_ from hablar:
library(hablar)
x <- c(NA, 1, 0, -1)
if_else_(x > 0, T, F, missing = F)
which gives you
[1] FALSE TRUE FALSE FALSE