alternative to a for loop for replacing a subset of elements in a matrix with elements in a vector in R

StackOverflow https://stackoverflow.com/questions/17388997

  •  02-06-2022
  •  | 
  •  

Question

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]
}
Was it helpful?

Solution

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.

OTHER TIPS

You can use this:

myarray <- ifelse(outer(dates, mydates, `>`), rep(mycons, each=length(dates)), 1)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top