5

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.

0

4 Answers 4

5

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
Sign up to request clarification or add additional context in comments.

4 Comments

(+1) Nice vectorization.
Isnt filter used for moving average type of calculations ? Could you explain how the filter function is working in this context ? Thanks.
filter calculates a moving sum (for past values or for a window on both sides). If the moving sum isn't zero I turn it into a 1.
+1 Brilliant. I did think of rollapply but not of taking moving sum.
5

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

1 Comment

+1. I was trying to use apply function on index but didnt think of extracting the indexes using apply and then assigning all those to 1. Thanks for this logic.
3

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

5 Comments

Thanks for the reply. Could you explain why my loop was returning the y vector as all 1's. Why do I need a dataframe here ?
You were not correcting if j-6 was less than 1. Also data.frame are easier to work with.
+1. Would it be possible to put this into a function and then use apply ? Just curious how the sapply or lapply would be defined for this for loop.
See answers by David and CathG
Yes but there they are extracting indexes using apply and then assigning those to 1. I was asking how to convert the for loop here into lapply.
2
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

4 Comments

Thanks for the reply. Could you explain how you defined the function. I was looking for an *apply approach. How is that assignment <- 1 part working ?
@Anusha, I edited my answer to add an explanation, tell me if that's ok now or if you need me to detail it a bit more.
I understood that part. I am curious about {val:(max(val-6,1))}))]<-1 , the bracketting and the logic.
@Anusha I "re-organize" my answer so you can better see what goes with what : the function applied to each element of which(x==1) calculates the indices of y values that should be one but it is the whole unlisted result of sapply function (in this case 4 3 2 1 17 16 15 14 13 12 11 19 18 17 16 15 14 13) that really goes between the brackets. In the end, it's like writing y[c(4,3,2,1,17,16,15,14,13,12,11,19,18,17,16,15,14,13)]<-1. I hope I understood right you comment and that this answers it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.