Reputation: 37
In a vector composed of 0 and 1, the '1' should be preserved only if there are at least three consecutive '1'. Here is an example:
x=c(0,0,0,0,0,1,1,0,1,0,0,1,1,0,1,1,1,0,0,0)
x_consecutive=numeric()
for (i in 1:20)
x_consecutive[i]=((x[i]>0) & (x[i+1]>0) & (x[i+2]>0)) | ((x[i]>0) & (x[i+1]>0) & (x[i-1]>0)) | ((x[i]>0) & (x[i-1]>0) & (x[i-2]>0))
x_consecutive
[1] NA NA 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0
This works quite well for me, but I need to perform this operation for all rows of a matrix like this:
matrix(sample(c(0:1),50, replace=T), nrow=5, ncol=10)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 1 1 1 0 1 1 0 1
[2,] 0 0 0 0 0 1 1 1 0 0
[3,] 1 1 1 1 0 0 1 1 1 0
[4,] 1 0 0 1 0 0 0 0 1 1
[5,] 0 0 0 1 1 0 1 1 0 0
To be transformed into this:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 1 1 1 0 0 0 0 0
[2,] 0 0 0 0 0 1 1 1 0 0
[3,] 1 1 1 1 0 0 1 1 1 0
[4,] 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 0
Is there a some smooth solution?
Upvotes: 1
Views: 67
Reputation: 3587
Another approach using @akrun's m1
maybe
t(apply(m1,1,function(t) rep(ifelse(rle(t)$lengths>2,1,0),rle(t)$lengths)))
Or
t(apply(m1,1, function(t) with(rle(t), rep(as.integer(lengths>2),lengths))))
Upvotes: 0
Reputation: 887168
We can use rle
on the logical vector (x==1
), change the 'values' where the lengths
is less than 3 and are 1 to 'FALSE', use inverse.rle
to reconvert it back to the original vector.
x1 <- as.integer(inverse.rle(within.list(rle(x==1),
values[lengths < 3 & values] <- FALSE)))
x1
#[1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0
This can be applied to all the rows of the matrix
with apply
t(apply(m1, 1, FUN = function(x) as.integer(inverse.rle(within.list(rle(x==1),
values[lengths < 3 & values] <- FALSE)))))
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#[1,] 1 1 1 1 1 0 0 0 0 0
#[2,] 0 0 0 0 0 1 1 1 0 0
#[3,] 1 1 1 1 0 0 1 1 1 0
#[4,] 0 0 0 0 0 0 0 0 0 0
#[5,] 0 0 0 0 0 0 0 0 0 0
The above code can be also made slightly compact without undermining the efficiency by
t(apply(m1, 1, FUN = function(x) inverse.rle(within.list(rle(x),
values[lengths < 3] <- 0))))
NOTE: Here I am calling rle
only once and not many times.
m1 <- structure(c(1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 0L, 0L, 1L, 0L, 1L,
0L, 0L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 1L, 0L, 1L, 0L, 0L,
0L, 1L, 1L, 1L, 0L, 1L, 1L, 1L, 1L, 0L, 1L, 0L, 0L, 1L, 1L, 0L,
1L, 0L, 0L, 1L, 0L), .Dim = c(5L, 10L))
Upvotes: 3