qdwu February 2016

Problems with control statement if...else in R

I am a beginner in R and here's my code:

for (i in 1:7){
testing<-vector(length=(length(yy)-3))
if(all(yy[i:(i+2)]==0))
testing[i]<-1
else
testing[i]<-NA
}

yy refers to the following vector of length 10:

> yy
 [1] 1 0 0 0 0 1 0 1 0 1

testing is like a predict function output, which will predict a 1 if the previous 3 elements in yy are all 0.If not, it will not predict anything, and so NA. Since yy has a total of 10 elements, testing will have a total of 7 elements (Therefore length 7) However, instead of giving me a output of 1s and NAs, it is giving this:

> testing
[1] FALSE FALSE FALSE FALSE FALSE FALSE    NA

I cannot figure out why, some help will be great. Thank you.

Answers


DatamineR February 2016

You should define testing outside the loop:

testing<-vector(length=(length(yy)-3))
for (i in 1:7){
    if(all(yy[i:(i+2)]==0))
        testing[i]<-1
    else
        testing[i]<-NA
}

 testing
[1] NA  1  1 NA NA NA NA

For this task you couls also use rollapply from zoo:

library(zoo)
rollapply(yy, 3, function(x) ifelse(all(x == 0), 1, NA))
[1] NA  1  1 NA NA NA NA NA


David Arenburg February 2016

Here are some additional vectorized ways of solving this

Base r stats::filter

N <- 3
NA^(stats::filter(yy == 0, rep(1, N), sides = 1)[-(1:N-1)] != N)
# [1] NA  1  1 NA NA NA NA NA

data.table::shift

NA^(Reduce(`+`, data.table::shift(yy == 0, 0:(N-1)))[-(1:N-1)] != N)
# [1] NA  1  1 NA NA NA NA NA

RcppRoll::roll_sum

NA^(RcppRoll::roll_sum(yy == 0, N) != N)
# [1] NA  1  1 NA NA NA NA NA

Some becnmarks (I've also added a compiled version of the for loop using compiler::cmpfun and two more efficient zoo solutions)

ForLoop <- function(yy, N){
  testing<-vector(length=(length(yy)-N))
  for (i in 1:length(testing)){
    if(all(yy[i:(i+(N-1))]==0))
      testing[i]<-1
    else
      testing[i]<-NA
  }
  testing
}

ForLoopBin <- compiler::cmpfun(ForLoop)

ZOO <- function(yy, N) zoo::rollapply(yy, N, function(x) ifelse(all(x == 0), 1, NA))

ZOO2 <- function(yy, N) NA^!zoo::rollapply(yy == 0, N, all)

ZOO3 <- function(yy, N) NA^(zoo::rollsum(yy == 0, N) != N)

RCPPROLL <- function(yy, N) NA^(RcppRoll::roll_sum(yy == 0, N) != N)

BaseFilter <- function(yy, N) NA^(stats::filter(yy == 0, rep(1, N), sides = 1)[-(1:N-1)] != N)

DTShift <- function(yy, N) NA^(Reduce(`+`, data.table::shift(yy == 0, 0:(N-1)))[-(1:N-1)] != N)

set.seed(123)
yy <- sample(0:1, 1e4, replace = TRUE)
N <- 3

library(microbenchmark)
microbenchmark(
  "for loop" = ForLoop(yy, N),
  "Compiled for loop" = ForLoopBin(yy, N),
  "zoo1" = ZOO(yy, N),
  "zoo2" = ZOO2(yy, N),
  "zoo3" = ZOO3(yy, N),
  "Rcpproll" = RCPPROLL(yy, N),
  "stats::filter" = BaseFilter(yy, N),
  "data.table::shift" = DTShift(yy, N)
)

# Unit: microseconds
#              expr        min         lq        mean      median          uq        max neval    cld
#          for loop  25917.837  26858 

Post Status

Asked in February 2016
Viewed 1,426 times
Voted 5
Answered 2 times

Search




Leave an answer