I have some numeric vectors of various lengths. Each of them may contain three types of values: 0s, 1s and -1s, but mostly 0s. I would like to replace 0s with neighboring values based on 2 conditions (both of them must be met for replacement): (I) if there are less than three 0s in the row (one by one), and (II) this string is surrounded on both sides by the same non-zero values.
For instance, if there would be: 1,1,1,1,0,1,1, I would like to replace the 0 for 1. On the other hand, if there would be: 1,1,-1,1,0,-1,-1, I would like to leave it unchanged.
I wrote a function for doing this, although this is not an elegant one. I tried to manage to handle both conditions at once - unfortunately R threw errors while I attempted to do so.
Here are some dummy vectors:
x <- c(1,0,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,-1,0,0,0,0,1,1,0,0,0,1)
y <- c(0,0,-1,0,-1,0,-1,-1,-1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,1,0,1,0,0,0)
z <- c(0,0,0,0,1,0,1,0,1,0,1,0,-1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,-1,0,1,0,-1,0,1,0,0,0,0,0,0,0,0,0)
a <- c(0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,-1,0,0,0,0,0,0)
Here are desired outputs:
x_desired <- c(1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, -1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1)
y_desired <- c(0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0)
z_desired <- c(0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
a_desired <- c(0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0)
And here is my function:
substitute_plus_and_minus <- function(x){
# create the run length encoding
mod_rle <- rle(x)
# create an index of 0s to be changed for 1s
one_substitute <- mod_rle$lengths <3 &
mod_rle$values == 0 &
c(utils::tail(mod_rle$values, -1) == 1, FALSE) &
c(FALSE, utils::head(mod_rle$values, -1) == 1)
# set the values to 1
mod_rle$values[one_substitute] <- 1
# recreate the original vector
x <- inverse.rle(mod_rle)
# create the run length encoding
mod_rle <- rle(x)
# create an index of 0s to be changed for -1s
minus_one_substitute <- mod_rle$lengths <3 &
mod_rle$values == 0 &
c(utils::tail(mod_rle$values, -1) == -1, FALSE) &
c(FALSE, utils::head(mod_rle$values, -1) == -1)
# set the values to -1
mod_rle$values[minus_one_substitute] <- -1
# recreate the original vector
x <- inverse.rle(mod_rle)
return(x)
}
I am looking for more elegant and compact solution (preferably base R approach), so there would be no need to iterate the data twice.
Try this:
The use of
Infin the determination ofindis purely to have something non-match (andNAdoes not work here).