Reputation: 5789
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
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
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