views:

60

answers:

2

Hi guys!

I've got a first vector, let's say x that consists only of 1's and -1's. Then, I have a second vector y that consists of 1's, -1's, and zeros. Now, I'd like to create a vector z that contains in index i a 1 if x[i] equals 1 and a 1 exists within the vector y between the n precedent elements (y[(i-n):i])...

more formally: z <- ifelse(x == 1 && 1 %in% y[(index(y)-n):index(y)],1,0)

I'm looking to create such a vector in R without looping or recursion. The proposition above does not work since it does not recognize to take the expression y[(index(y)-n):index(y)] element by element.

Thanks a lot for your support

+1  A: 

You could use apply like this, although it is essentially a pretty way to do a loop, I'm not sure if it will be faster (it may or may not).

y1 <- unlist(lapply(1:length(x), function(i){1 %in% y[max(0, (i-n)):i]}))
z <- as.numeric(x==1) * as.numeric(y1)
nico
Hi Nico,Thanks a lot for your prompt and very helpful comment, I'll check the speed, but i'm rather convinced that your solution is faster than an ordinary loop in R.Cordially,martin
martin
+2  A: 

Here's an approach that uses the cumsum function to test for the number of ones that have been seen so far. If the number of ones at position i is larger than the number of ones at position i-n, then the condition on the right will be satisfied.

## Generate some random y's.
> y <- sample(-1:1, 25, replace=T)
> y
 [1]  0  1 -1 -1 -1 -1 -1  1 -1 -1 -1 -1  0  0 -1 -1 -1  1 -1  1  1  0  0  0  1
> n <- 3
## Compute number of ones seen at each position.
> cs <- cumsum(ifelse(y == 1, 1, 0))
> lagged.cs <- c(rep(0, n), cs[1:(length(cs)-n)])
> (cs - lagged.cs) > 0
 [1] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE  TRUE  TRUE FALSE FALSE
[13] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
[25]  TRUE
Jonathan Chang
Nice one! I thought of using `cumsum` too but couldn't figure out how to implement the lag.
nico
wow, thanks a lot to your help
martin