Why I didn't get the answer I expected? - r

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)

Related

The logical comparison inside the loop crashes when it encounters zero

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)

Cut elements from the beginning and end of an R vector

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

How to replace all negative values in vector by 0 in R

I have a randomly generated vector from a normal distribution with 50 elements
vector<-c(rnorm(50))
I want to change all negative values to 0 and positive values to 1
I used this function and indexing however then I do not get vector with 50 elements
vector[ vector< 0 ] <- 1
vector[ vector> 0 ] <- 0
How should I proceed?
Generate some data
x = rnorm(50)
then either
x = ifelse(x > 0, 1, 0)
or
x[x < 0] = 0
x[x > 0] = 1
Or even better
as.numeric (x>0)
However since the standard normal is symmetric about 0, why not simulate directly via
sample(0:1, 50, replace=TRUE)
The problem is that in the first query you replace all value smaller 0 by values larger zero
so the trick is to switch
vector[ vector< 0 ] <- 1
vector[ vector> 0 ] <- 0
into
vector[ vector> 0 ] <- 0
vector[ vector< 0 ] <- 1
Note that you are also slightly biased towards 0 but that should only be marginal

Random walk sum of values greater than 0 in R

I want to write a function such that rwabovex is the sum of the values of S that are greater than 0. (My S is a random walk simulation)
Here's what I have so far but I'm not getting the right output. Can you please help?
rwabovex=function(n){
if (n <= 0) {
return(cat("n must be greater than 0"))
} else {
S=numeric(n)
S[1] = 0
above = 0
for(i in 2:n) {
step=c(1, -1)
S[i]=S[i-1]+sample(step, 1, prob = c(0.5, 0.5), replace = TRUE)
if (S[i] > 0) {
above = above + S[i]
}
print(above)
}
}
}
For example: if n=4 and the S values are -1, 2, 1, 0 then "above" should equal to 3 (since 2 and 1 are greater than 0).
Thanks!
First, you're not using vectorization to compute S, which will make the procedure slow for large n. You can vectorize using cumsum. Secondly, you can use sum to compute the sum of values in S greater than 0:
rwabovex = function(n) {
step = c(1, -1)
S = c(0, cumsum(sample(step, n-1, prob=c(.5, .5), replace=T)))
print(S)
return(sum(S[S > 0]))
}
set.seed(144)
rwabovex(10)
# [1] 0 -1 0 1 2 1 2 1 2 1
# [1] 10

How to prevent NULL from killing my ifelse vectorising?

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

Resources