16

I want to run a function on all periods of an xts matrix. apply() is very fast but the returned matrix has transposed dimensions compared to the original object:

> dim(myxts)
[1] 7429   48
> myxts.2 = apply(myxts, 1 , function(x) { return(x) })
> dim(myxts.2)
[1]   48 7429
> str(myxts)
An 'xts' object from 2012-01-03 09:30:00 to 2012-01-30 16:00:00 containing:
  Data: num [1:7429, 1:48] 4092500 4098500 4091500 4090300 4095200 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:48] "Open" "High" "Low" "Close" ...
  Indexed by objects of class: [POSIXlt,POSIXt] TZ: 
  xts Attributes:  
 NULL
> str(myxts.2)
 num [1:48, 1:7429] 4092500 4098500 4091100 4098500 0 ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:48] "Open" "High" "Low" "Close" ...
  ..$ : chr [1:7429] "2012-01-03 09:30:00" "2012-01-03 09:31:00" "2012-01-03 09:32:00" "2012-01-03 09:33:00" ...
> nrow(myxts)
[1] 7429
> head(myxts)
                       Open    High     Low   Close
2012-01-03 09:30:00 4092500 4098500 4091100 4098500
2012-01-03 09:31:00 4098500 4099500 4092000 4092000
2012-01-03 09:32:00 4091500 4095000 4090000 4090200 
2012-01-03 09:33:00 4090300 4096400 4090300 4094900
2012-01-03 09:34:00 4095200 4100000 4095200 4099900
2012-01-03 09:35:00 4100000 4100000 4096500 4097500 

How can I preserve myxts dimensions?

Robert Kubrick
  • 8,413
  • 13
  • 59
  • 91

1 Answers1

21

That's what apply is documented to do. From ?apply:

Value:

 If each call to ‘FUN’ returns a vector of length ‘n’, then ‘apply’
 returns an array of dimension ‘c(n, dim(X)[MARGIN])’ if ‘n > 1’.

In your case, 'n'=48 (because you're looping over rows), so apply will return an array of dimension c(48, 7429).

Also note that myxts.2 is not an xts object. It's a regular array. You have a couple options:

  1. transpose the results of apply before re-creating your xts object:

    data(sample_matrix)
    myxts <- as.xts(sample_matrix)
    dim(myxts)    # [1] 180   4
    myxts.2 <- apply(myxts, 1 , identity)
    dim(myxts.2)  # [1]   4 180
    myxts.2 <- xts(t(apply(myxts, 1 , identity)), index(myxts))
    dim(myxts.2)  # [1] 180   4
    
  2. Vectorize your function so it operates on all the rows of an xts object and returns an xts object. Then you don't have to worry about apply at all.

Finally, please start providing reproducible examples. It's not that hard and it makes it a lot easier for people to help. I've provided an example above and I hope you can use it in your following questions.

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • If I want to go for option 2, how can I pass each full row to my processing function? For example, myxts$result = myxts$Close - myxts$Open works for specific fields, but what if I want to call a function passing in the full row as one of the parameters? – Robert Kubrick Mar 01 '12 at 18:13
  • 1
    @RobertKubrick: I can't answer that without seeing your function. It may or may not be possible. At minimum, you could wrap your processing function in another function that does option 1. It won't truly be vectorized, but it will be cleaner if you're going to do it a lot. – Joshua Ulrich Mar 01 '12 at 18:19
  • Solution 1 is very fast compared to a for loop. Would like to understand why but maybe that's a different question. – Robert Kubrick Mar 01 '12 at 18:19
  • @RobertKubrick It is due to it being an interpreted language. http://stackoverflow.com/questions/7142767/why-are-loops-slow-in-r – Nicholas Hamilton Sep 11 '13 at 01:55