Vassilis Chasiotis
Vassilis Chasiotis

Reputation: 439

How to count the number of same elements which are in order in a vector in R?

I have for example a vector like this one:

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

and I want the algorithm to product a vector (3,1,6,2,2,7,1)

which means 3 of "1s", 1 of "-1s", 6 of "1s" etc...

I have developed the following algorithm but it doesn't work for every vector x, which probably I am going to have.

y<-c(0)
q=0
z=0
w=0
e=1

if (x[1]==1)
{
q<-abs(sum(x[1:(min(which(x < 0))-1)]))
y[e]<-q
k=q+1
z<-abs(sum(x[k:min(which(x < 0))]))
e=e+1
y[e]<-z
k=k+z
r<-matrix(c(which(x < 0)))
w<-matrix(c(which(x > 0)))

while( k<22 )

{

if( all(r<k) )
{
z<-sum(x[k:22])
e=e+1
y[e]<-z
k=k+z
}else
{
z<-abs(sum(x[k:min(r[which(r > k)]-1)]))
e=e+1
y[e]<-z
k=k+z
}

if( all(w<k) )
{
z<-abs(sum(x[k:22]))
e=e+1
y[e]<-z
k=k+z
}else
{z<-abs(sum(x[k:min(w[which(w > k)]-1)]))
e=e+1
y[e]<-z
k=k+z
}

}}

But for the vector x<-c(1,1,1, -1, 1,1,1,1,1,1, -1,-1, 1,1, -1,-1,-1,-1,-1,-1,-1,-1) it works.

Do you have any idea to do this faster and easier or just to find the problem in my own code??

Thank you all!

Upvotes: 3

Views: 154

Answers (2)

Cath
Cath

Reputation: 24074

you can try function rle:

rle(x)
#Run Length Encoding
#  lengths: int [1:7] 3 1 6 2 2 7 1
#  values : num [1:7] 1 -1 1 -1 1 -1 1

and so rle(x)$lengths gives you what you want:

rle(x)$lengths
#[1] 3 1 6 2 2 7 1

Efficiency comparison between @clemlaflemme functions and rle:

library(microbenchmark)

x <- rep(x,5000)

microbenchmark(clem_shift(),cath_rle(),clem_cumul(),unit="relative")
#Unit: relative
#         expr        min        lq        mean     median         uq        max neval cld
# clem_shift()   1.000000   1.00000   1.0000000   1.000000   1.000000  1.0000000   100  a 
#   cath_rle()   1.181513   1.13419   0.8552573   1.095478   1.041918  0.9483564   100  a      
# clem_cumul() 325.480391 284.14827 170.1371421 265.160409 241.954976 54.5240969   100   b

Upvotes: 10

ClementWalter
ClementWalter

Reputation: 5324

Just for information, you could have written this small piece of code to sort out this by yourself

cumul = c()
cur = 1
for(i in 2:length(x)){
   if(x[i] == x[i-1]) cur = cur + 1
   else{
       cumul = c(cumul, cur)
       cur = 1
   }
}
cumul = c(cumul, cur)

But of course, using rle function is simpler. After @CathG comments, an other hand written function you could have think of if using only 0 and 1:

clem = function(X){
    shift = c(0,seq(X)[as.logical(c(X[-1] - head(X,-1), 1))])
    shift = shift[-1] - head(shift,-1)
    return(shift)
}

And then the benchmark against rle:

X = runif(1000)<0.5
> microbenchmark(cath(),clem(),unit = "relative")
Unit: relative
   expr      min      lq     mean   median       uq     max neval
 cath() 1.115647 1.10824 1.220533 1.102692 1.098195 9.22847   100
 clem() 1.000000 1.00000 1.000000 1.000000 1.000000 1.00000   100

Upvotes: 3

Related Questions