user189035
user189035

Reputation: 5789

Increment values in vector conditionally (conditional restarting running sum)-- vectorized version?

Given a vector of binary values out_2 the code below returns a vector of same length as out_2 called out_1. The entries of out_1 counts the number of successive similar items left in out_2 before the next sign switch. If you print the final cbind() I think you will see what I mean.

  library(zoo)
  n = 10
  out_2 = rep(NA, n)
  out_2[sample.int(n, 3)] = sample(c(-1, 1), 3, replace = TRUE)
  out_2 = zoo::na.locf(out_2)
  out_1 = out_2
  out_1[length(out_2)] = 1
  for(i in (length(out_2) - 1):1){
    out_1[i] = ifelse(out_2[i + 1] == out_2[i], out_1[i + 1] + 1, 1)  
  }
cbind(out_1, out_2)

I was wondering if there is a one liner vectorized way to get out_1 from out_2 (i.e. vectoring the explicit for loop)?

Upvotes: 0

Views: 57

Answers (2)

Yannis Vassiliadis
Yannis Vassiliadis

Reputation: 1709

I would use rle from base R. The tricky part is to get the reverse order for the out_1 vector, so it has (?) to go through `lapply'

out_1<- unlist(lapply(rle(out_2)$lengths, function(x) seq(x, by=-1)))

And the result is:

cbind(out_1, out_2)
      out_1 out_2
 [1,]     2    -1
 [2,]     1    -1
 [3,]     1     1
 [4,]     6    -1
 [5,]     5    -1
 [6,]     4    -1
 [7,]     3    -1
 [8,]     2    -1
 [9,]     1    -1

If you're flexible with the output and you don't need it to be in reverse order, you can simply use the sequence function.

out_1<- sequence(rle(out_2)$lengths)
cbind(out_1, out_2)
      out_1 out_2
 [1,]     1    -1
 [2,]     2    -1
 [3,]     1     1
 [4,]     1    -1
 [5,]     2    -1
 [6,]     3    -1
 [7,]     4    -1
 [8,]     5    -1
 [9,]     6    -1

Upvotes: 3

pogibas
pogibas

Reputation: 28339

This solution iterates over grouped consecutive values (not over out_2 as in your example). Basically, we group consecutive values, check how large this group is and create vector N:1.

foo <- rle(out_2)
cbind(unlist(sapply(foo$lengths, function(x) x:1)), 
      rep(foo$values, foo$lengths))

Upvotes: 1

Related Questions