user1627466
user1627466

Reputation: 423

R vector :removing values conditioned on surrounding values

This may not be the best title, feel free to edit it.

 x=c(NA,NA,NA,1,NA,NA,NA,NA,0,NA,NA,NA,1,NA,NA,0,NA,NA,NA,NA,1,NA,NA,NA,0,NA....)

or

 x=c(NA,NA,NA,0,NA,NA,NA,NA,1,NA,NA,NA,0,NA,NA,1,NA,NA,NA,NA,0,NA,NA,NA,1,NA....)
 y=c(seq(1:length(x)))

I would like z to be a new vector that is equal to y except when NAs are between 0 and 1 (not 1 and 0) where it should repeat the value taken when x=0

 [1]  1  2  3  4  5  6  7  8  9  9  9  9 13 14 15 16 16 16 16 16 21 22 23 24 25 25

or

 [1]  1  2  3  4  4  4  4  4  9 10 11 12 13 13 13 16 17 18 19 20 21 21 21 21 25 26

depending on x I really don't know how to translate this condition in R.

Upvotes: 1

Views: 120

Answers (3)

Carl Witthoft
Carl Witthoft

Reputation: 21492

Another approach:

 y0 <- which(x==0)
 y1<-which(x==1)
 # need a kicker to start with first zero
 y1<-y1[y1>y0[1]]
 # and check for end of sequence
 if(y1[length(y1)]< length(x)) y1[(length(y1)+1] <- length(x)+1
 #now y0 and y1 better be same length
 z<-y
 #now do a loop any way you want
 for (jj in 1: length(y0) ) z[y0[jj]:(y1[jj]-1)]<-y[y0[jj]]

Rgames> z
 [1]  1  2  3  4  4  4  4  4  9 10 11 12 13 13 13 16 17 18 19 20 21 21 21 21 25
[26] 26

Upvotes: 2

brett
brett

Reputation: 21

If time isn't prohibitive, you can just use a "for" loop:

z <- y 
between.0.1 <- rep(FALSE, length(x))
for(i in 2:length(x)){
    if(!is.na(x[i-1]) && x[i-1]==0){  # switch on after a 0
        between.0.1[i] <- TRUE  
        value.at.0 <- y[i-1]
        z[i] <- value.at.0
     }
     if(between.0.1[i-1]){  # if switched on, stay switched on 
        between.0.1[i] <- TRUE  
        z[i] <- value.at.0
     }    
     if(!is.na(x[i]) && x[i]==1){  # switch off if at a 1
        between.0.1[i] <- FALSE  
        value.at.0 <- NA
     }
 }    
 z[between.0.1] # diagnostic check

Upvotes: 2

Ben Bolker
Ben Bolker

Reputation: 226097

My solution is clunkier than @James's (now deleted) answer but maybe (?) it's more flexible:

## identify strings of NAs preceded by 0
library(zoo)
na_following_zero <- na.locf(c(1,x))[-1]==0 & is.na(x)
## now identify the 'chunks' to reset
## (there may be a more elegant way to do this)
rr <- rle(na_following_zero)
startvals <- cumsum(c(0,rr$lengths))+1
endvals <- cumsum(rr$lengths)
values <- c(NA,y[startvals-1])
z <- y
## replace values in chunks
for (i in seq_along(rr$values)[rr$values])
    z[startvals[i]:endvals[i]] <- values[i]

Upvotes: 3

Related Questions