Michael Henning
Michael Henning

Reputation: 77

Conditional Flag in R

I'm trying to create a variable that holds a value and that is reset when it reaches another predefined values.

For instance. I have some data stored in a vector. In another vector (Result) I want to set the value to -1 when the value in x <= -.50 until x > 0. Same thing if x is >= .50 set value to 1 until x < 0.

x <- c(-.28 , -.32, -.38, -.49, -.52, -.44, -.33, -.28, -.16, 0, .18, .22, .33, .42, .52, .32, .26, 0, -.10, -.15)

Result <- c(0, 0, 0, 0, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0 , 1, 1, 1, 0, 0 ,0)

Comb <- data.frame(x, Result)

I can evaluate these conditions individually but I can't figure out how to set a conditional flag that's reset-able.

Thanks

Mike

Upvotes: 3

Views: 879

Answers (3)

bgoldst
bgoldst

Reputation: 35314

Here's an Rcpp solution:

library(Rcpp);
cppFunction('
    IntegerVector hysteresisRangeFlagWithReset(DoubleVector x,double low,double high,double reset) {
        IntegerVector res(x.size());
        if (x.size()==0) return res;
        res[0] = x[0]<=low ? -1 : x[0] >= high ? 1 : 0;
        for (int i = 1; i < x.size(); ++i)
            res[i] =
                x[i]<=low ? -1 :
                x[i]>=high ? 1 :
                x[i-1]<reset && x[i]>=reset || x[i-1]>reset && x[i]<=reset ? 0 :
                res[i-1]
            ;
        return res;
    }
');
hysteresisRangeFlagWithReset(x,-0.5,0.5,0)
##  [1]  0  0  0  0 -1 -1 -1 -1 -1  0  0  0  0  0  1  1  1  0  0  0

Data

x <- c(-0.28,-0.32,-0.38,-0.49,-0.52,-0.44,-0.33,-0.28,-0.16,0,0.18,0.22,0.33,0.42,0.52,0.32,
0.26,0,-0.10,-0.15);

Upvotes: 1

akuiper
akuiper

Reputation: 214927

Here is a vectorized approach using na.locf from zoo package. Since the result only changes values at positions where the absolute value is larger than 0.5 or the value is switching sign, we can find out these positions, fill with corresponding values and fill forward using the na.locf function supposing we are starting from a vector of NAs:

library(magrittr); library(zoo)

# start from a vector of NA of the same length of the vector
rep(NA, length(x)) %>% 
    # place 0 at positions wherever there is a sign change
    replace(c(T, diff(sign(x)) != 0), 0) %>%   
    # place +1 or -1 at positions wherever the absolute value is larger than 0.5
    replace(abs(x) >= 0.5, sign(x[abs(x) >= 0.5])) %>% 
    # fill the NA with the previous values -1, 0 or 1
    na.locf()

# [1]  0  0  0  0 -1 -1 -1 -1 -1  0  0  0  0  0  1  1  1  0  0  0

Upvotes: 3

Hack-R
Hack-R

Reputation: 23214

x      <- c(-.28 , -.32, -.38, -.49, -.52, -.44, -.33, -.28, -.16, 0, .18, .22, .33, .42, .52, .32, .26, 0, -.10, -.15)
Result <- c(0, 0, 0, 0, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0 , 1, 1, 1, 0, 0 ,0)
Comb   <- data.frame(x, Result)

for(i in 1:nrow(Comb)){
  if(Comb$x[i] <= -.5){
    Comb$Result[i:nrow(Comb)] <- -1
  } 
  if(Comb$x[i] >= .5){
    Comb$Result[i:nrow(Comb)] <- 1
  }
  if(i > 1){
    if(Comb$Result[i-1] == 1 & Comb$x[i] < 0 & Comb$x[i] > -.5){
      Comb$Result[i:nrow(Comb)] <- 0
    }
  }
  if(i > 1){
    if(Comb$Result[i-1] == -1 & Comb$x[i] > 0 & Comb$x[i] < .5){
      Comb$Result[i:nrow(Comb)] <- 0
    }
  }
  if(Comb$x[i]==0){
    Comb$Result[i] <- 0 # Based on the example data, not the narrative
  }
  if(i > 1){
    if(Comb$Result[i-1] == 0 & Comb$x[i] < .5 & Comb$x[i] > -.5){
      Comb$Result[i] <- 0
    }
  }
}

identical(Comb$Result, Result)

TRUE

Upvotes: 3

Related Questions