Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to construct this binary variable in R?

Tags:

r

The aim is check if value at index i is 1 and then make the previous six entries as 1.

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

## Required output 
y <- c(1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)

## Attempt 
for(j in seq_along(x)){
if(x[j] == 1){
   for(i in (j-6):j)
   x[i] = 1
   }}

Could you help solve this or better approach ?

Thanks.

like image 248
Anusha Avatar asked Nov 13 '14 12:11

Anusha


4 Answers

A fully vectorized solution using filter:

as.integer( #turn logical value into numbers
  as.logical( #coerce to logical --> 0 becomes FALSE, everything else TRUE
   rev( #reverse order
    filter( #linear filtering
      c(rep(0, 6), #pad with zeros in the beginning to avoid NAs
        rev(x)), #revers order of input vector
          c(rep(1, 7)), sides=1 #y_i = x_i * 1 + x_(i-1) * 1 +...+ x_(i-6) * 1 
  )[-(1:6)]))) #remove NA values

#[1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
like image 192
Roland Avatar answered Oct 07 '22 06:10

Roland


You could try the following options (though don't forget to initialize x when trying each option as I'm overriding it)

indx <- mapply(function(x, y) x:y, which(x == 1) - 6 , which(x == 1))
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

Or even simpler

indx <- sapply(which(x == 1) - 6, function(x) x:(x + 6))
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

Or

indx <- apply(cbind(which(x == 1) - 6 , which(x == 1)), 1, function(x) x[1]:x[2])
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

Or

indx <- seq_len(6)
indx <- sapply(which(x == 1), function(x) x - indx)
x[indx[indx > 0]] <- 1
x
## [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
like image 35
David Arenburg Avatar answered Oct 07 '22 06:10

David Arenburg


Using 'for' loop:

ddf = data.frame(x,y=0)
for(i in 1:nrow(ddf)){
    if(ddf[i,'x']==1){
        j = i-5
        if(j<1) j=1
        ddf[j:i,'y'] = 1
    }
}
ddf
   x y
1  0 1
2  0 1
3  0 1
4  1 1
5  0 0
6  0 0
7  0 0
8  0 0
9  0 0
10 0 0
11 0 0
12 0 1
13 0 1
14 0 1
15 0 1
16 0 1
17 1 1
18 0 1
19 1 1

y = ddf$y
y
 [1] 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
like image 3
rnso Avatar answered Oct 07 '22 07:10

rnso


y<-x
y[unlist(sapply(which(x==1),
                function(val){
                   val:(max(val-6,1))
                 }
                )
        )
  ]<-1

> y
 [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1

Explanation :

I first look for indices of x=1 with which(x==1). Then, for each of the indices I get the indices from the one with x=1 to the 6th before that with sapply(...) then I unlist the result to only have a vector of indices for which y must be 1. I then assigned 1 to the corresponding y values.

another writing, in 2 steps :

y<-x
ind<-unlist(sapply(which(x==1),function(val){val:(max(val-6,1))}))
y[ind]<-1

> y
 [1] 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1
like image 2
Cath Avatar answered Oct 07 '22 07:10

Cath