tags:

views:

343

answers:

2

I have two vectors, "subject" and "target". I want to create a new vector based on comparisons between the two existing vectors, with elements being compared "lagged". I've solved this okay using the loop below, but I'm essentially wondering whether there's a more elegant solution using apply?

subject <- c(200,195,190,185,185,185,188,189,195,200,210,210)
target <- c(subject[1],subject[1]-cumsum(rep(perweek,length(subject)-1)))
adjtarget <- target                                               
 for (i in 1:(length(subject)-1)) {
 if (subject[i] > adjtarget[i]) {                
   adjtarget[i+1] <- adjtarget[i]           
 } else {                                       
 adjtarget[i+1] <- adjtarget[i]-perweek  }
 }
 }

(I hope this code is still correct. Frankly, I find the way of entering code here at stackoverflow.com, with only indentation to go by, bewildering)

+1  A: 

This doesn't exactly solve your problem, but may point in a helpful direction. I'm disregarding the interplay between changing adjtarget and comparing to it, and show a similar problem, where we compare to the constant target. Then it's possible to change the if in the loop to a vector comparison:

lv <- but.last(subject) > but.last(target)
ind <- which(lv)

Prepare the result vector (I'll call it x, as it won't be the same result as your adjtarget) as a shifted copy of target and assign the changes to it:

x <- c(target[1], but.last(target))  # corresponds to the true branch of the `if`
x[ind+1] <- target[ind] - perweek    # corresponds to the false branch

Alternatively,

x <- c(target[1], but.last(target) - (!lv)*perweek

As I said, this doesn't solve your problem, but perhaps we could start from here.

Florian Jenn
+1  A: 

Just for clarification, if I understand your code, this is the kind of result you're looking for...

> (goal <- cbind(subject,target,adjtarget))

      subject target adjtarget
 [1,]     200    200       200
 [2,]     195    198       198
 [3,]     190    196       196
 [4,]     185    194       194
 [5,]     185    192       192
 [6,]     185    190       190
 [7,]     188    188       188
 [8,]     189    186       186
 [9,]     195    184       186
[10,]     200    182       186
[11,]     210    180       186
[12,]     210    178       186

If I'm right, then the challenge to vectorizing this is the repeated assignment of 186 in adjtarget. Vectorized code will evaluate the right hand side (RHS) before assigning it to the left hand side (LHS). So, the vectorized code won't see the updated value in adjtarget at row 9 until after the assignment is finished.

> y <- ifelse(subject > target, 1, 0) # matches TRUE case
> x <- target
> x[ind+1] <- target[ind]
> cbind(goal, x, y)
      subject target adjtarget   x y
 [1,]     200    200       200 200 0
 [2,]     195    198       198 198 0
 [3,]     190    196       196 196 0
 [4,]     185    194       194 194 0
 [5,]     185    192       192 192 0
 [6,]     185    190       190 190 0
 [7,]     188    188       188 188 0
 [8,]     189    186       186 186 1
 [9,]     195    184       186 186 1 # assigned correctly (?)
[10,]     200    182       186 184 1 # incorrect x; should be 186
[11,]     210    180       186 182 1 # incorrect x; should be 186
[12,]     210    178       186 180 1 # incorrect x; should be 186
William Doane