2

I'm using a for loop to replace a subset of elements of myarray using mycons vector. The subset in each column would be from mydatesuntil the end. Is there an alternative to the for loop?

mydates <- as.Date(c('2013-06-05','2013-06-16','2013-06-22'))
mycons <- c(0.5,1/7,0.25)
dates <- seq(as.Date('2013-06-01'),Sys.Date(),"days")
myarray <- matrix(rep(1,length(dates)*length(mydates)),length(dates),length(mydates))

for (i in 1:length(mycons)) {
  myarray[which(dates>mydates[i]),i] <- mycons[i]
}
nopeva
  • 1,583
  • 5
  • 22
  • 38
  • 1
    Is this actually your data? Or is this a simplified version? Because as written this is both fast and probably doesn't require a `for` loop at all because you seem to just be recoding your data in a fairly straightforward way. – Thomas Jun 30 '13 at 09:46
  • So, do you want help with that error? If so, update your question. Or, do you want to talk about ways of generating your `myarray` matrix? – Thomas Jun 30 '13 at 10:05
  • @Thomas I'm sorry, I though that understood your point but now I can't get the code to work if remove the `for` loop. I would appreciate if you could help me with different ways of generating `myarray`. – nopeva Jun 30 '13 at 21:49
  • Update your question by describing what your intended `myarray` should look like. Then people can help you get your intended result rather than solve whatever issues you might be having with this particular code, which doesn't - on face value - look like a very good way of obtaining any result. – Thomas Jul 01 '13 at 08:08
  • @Thomas if the code were efficient I wouldn't have to ask here but it does what it is supposed to do. Thanks anyway for your initial support. – nopeva Jul 01 '13 at 09:34

2 Answers2

1

The items you are comparing are of different classes: character and Dates. (I get an entire matrix filled with 1's.)

Try this:

 mydates <- as.Date(mydates) # then the comparisons will more sensible

It get to a vectorized answer I resorted to the use of outer and rearranged the logic a bit to create a matrix with the "new" values, and then set the failing items back to strating value of 1:

myarray2 <-matrix(mycons, 
                nrow=length(dates), ncol=length(mydates), byrow=TRUE)
myarray2[  outer(dates, mydates, "<=") ] <- 1
myarray2

I tried using mapply thinking I could do something like to pass "parallel items" from two sequences but there is no way that I could get the "i" indexing to take hold.

mapply(function(x,y) {myarray[i , ] <- y[x>dates]} , mydates, mycons)

Typical reworking of for-loop: You can pretty much always reconstruct a for-loop as an sapply operation:

 sapply( 1:length(mycons), function(idx){ 
          myarray[which(dates>mydates[idx]),idx] <- mycons[idx]; myarray[,idx]})

I suspect someone can construct a sweep operation that would do this but I have not really grokked sweep yet.

If you want to take the path that @Ferdinand.Kraft is suggesting of building a vector of the same length as myarray, but stay within the paradigm of obj[cond] <- value then do this:

 myarray[  outer(dates, mydates, ">") ] <- 
        rep(mycons, each=length(dates) )[ outer(dates, mydates, ">")]

It's an illustration of using conditional assignment by applying the same condition to both sides of an <- operation. It can be quite fast.

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • thanks I've updated the code. Do you know of an alternative to the `for` loop for this? – nopeva Jul 01 '13 at 09:37
  • I can think of a possible equivalent call to `mapply`, but I don't understand why you would need to. `for`-loops are just as fast for this sort of operation. – IRTFM Jul 01 '13 at 16:13
  • thanks for your help. I'm learning and often have read that it is recommended using vectorization instead of loops because of memory issues. Although the loop would fit better in this case, would you mind helping with a `mapply` version if is not too complicated? It would let me understand how it works. – nopeva Jul 01 '13 at 16:59
  • I won't mind helping if you make a smaller example. The last one created a huge output when I examined it. You should also consider reading the `mapply` help page and running examples at the bottom of that page. – IRTFM Jul 01 '13 at 17:01
  • I've reduced the dimension of `myarray`. With regard to the help page, I've read it but still don't understand it well, just know how to use the univariate ones. – nopeva Jul 01 '13 at 17:06
  • Many thanks for all those alternatives. Do you get an error in the sapply version with object `ì`? – nopeva Jul 01 '13 at 19:55
  • Will fix. Obviously meant to use `idx` throughout. – IRTFM Jul 01 '13 at 20:00
1

You can use this:

myarray <- ifelse(outer(dates, mydates, `>`), rep(mycons, each=length(dates)), 1)
Ferdinand.kraft
  • 12,579
  • 10
  • 47
  • 69