Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting vector of zeros and ones into groups

Tags:

r

I have a vector of zeros and ones, for example:

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

I need to convert this vector to another form:

c(0,0,1,1,1,0,0,0,0,2,2,2,0,0,3)

where subsequent natural numbers are going to indicate number of block of 'ones' from original vector in positions of that block. Basically I need solution which will compute fast ( x vector will be typically at least >30k long and there will be a multiple vectors like this in one run).

Any ideas that don't involve 'for' loops?

like image 309
cyzyk Avatar asked Mar 12 '23 21:03

cyzyk


2 Answers

This seems about as quick as I can find. All the options presented in this and @akrun's answer will be fractions of seconds for all but the most huge vectors.

replace(x, x!=0, cumsum(diff(c(0,x)==1)[x!=0]) )
# [1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3

And a further, possibly pointless way to do it:

replace(x, x!=0, factor(cumsum(x==0)[x!=0]) )
# [1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
like image 149
thelatemail Avatar answered Mar 20 '23 02:03

thelatemail


We can use rle

inverse.rle(within.list(rle(x), values[values!=0] <- seq_along(values[values!=0])))
#[1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3

Another option is rleid from data.table

library(data.table)
cumsum(!duplicated(rleid(x)) & x!=0)*x
#[1] 0 0 1 1 1 0 0 0 0 0 2 2 2 0 0 3
like image 34
akrun Avatar answered Mar 20 '23 03:03

akrun