The question looks simple but I didn't figure out how it can done in R. I want to modify a logical vector depending on patterns of its values. There are two modification steps:
Everything else should remain as it is. Here's an example:
# input
x = c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE)
# output
xo = c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE)
cbind(x,xo) is
x xo
[1,] FALSE FALSE
[2,] TRUE FALSE
[3,] FALSE FALSE
[4,] FALSE FALSE
[5,] TRUE FALSE
[6,] TRUE FALSE
[7,] FALSE FALSE
[8,] FALSE FALSE
[9,] TRUE TRUE
[10,] TRUE TRUE
[11,] TRUE TRUE
[12,] FALSE TRUE
[13,] TRUE TRUE
[14,] TRUE TRUE
[15,] FALSE FALSE
[16,] FALSE FALSE
[17,] TRUE TRUE
[18,] TRUE TRUE
[19,] TRUE TRUE
[20,] TRUE TRUE
[21,] FALSE FALSE
I dont want to use a for loop because its slow and I would have to do a lot of if statements.
Is there a better way to get this working?
Here is an approach:
#sample data
x <- c(FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE)
First, find the indices where FALSE values need to be changed to TRUE values, by looking for FALSE values that follow and are followed by TRUE values
tochange <-
intersect(
intersect(
which(x == FALSE), # not strictly necessary
which(diff(x) == 1) # FALSEs followed by a TRUE
),
which(diff(x) == -1) + 1 # FALSEs that follow a TRUE
)
Change the values
x[tochange] <- TRUE
Next, look for runs of TRUE (and FALSE) that are less than 3 in length, and set them to FALSE.
xrle <- rle(x)
xrle$values[xrle$lengths < 3] <- FALSE
newx <- inverse.rle(xrle) # thanks to Frank for pointing out inverse.rle!
# [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
#[10] TRUE TRUE TRUE TRUE TRUE FALSE FALSE TRUE TRUE
#[19] TRUE TRUE FALSE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With