joshuaulrich / xts

Extensible time series class that provides uniform handling of many R time series classes by extending zoo.
http://joshuaulrich.github.io/xts/
GNU General Public License v2.0
220 stars 71 forks source link

cbind support for deparse.level #358

Closed ethanbsmith closed 2 years ago

ethanbsmith commented 2 years ago

current cbind.xts does not support naming columns during the bind. this syntaxt can be very convenient vs having the capture the output followed by a colnames()<-

Desired behavior

from the base cbind docs:

deparse.level:
integer controlling the construction of labels in the case of non-matrix-like arguments (for the default method): deparse.level = 0 constructs no labels; the default, deparse.level = 1 or 2 constructs labels from the argument names, see the ‘Value’ section below.

I should add that i current use a wrapper function for this so if its complicated, not worth the trouble:

ApplyNames <- function (x, n) {
  names(x) <- n
  x
}

which allows me to do a single line like:

ApplyNames(cbind(foo,bar), c("foo", "bar"))
joshuaulrich commented 2 years ago

Can you give a reproducible example of a call to cbind(), its results, and your desired results? A dput() of the xts objects you use would be helpful.

ethanbsmith commented 2 years ago

my real world use case leverages a utility function ApplyTechnical <- function(Symbols, data, FUN, ...) that you can think of as a multithreaded version of eapply. it just farms function across a cluster, passing an OHLCV from a data cache. So im often writing code like: ApplyTechnical(Symbols, data, function(z){cbind(ROC(z, n= 5), ROC(z, n=20))}) What i do is use the cluster to do the costly calculations in scale then bring all the results together and rbind them into a data.table for analysis. I don't want to bring any of that complexity here, so here is a simple reproducible example:

z <- getSymbols("SPY", auto.assign = F)
cbind(z, roc20 = ROC(Cl(z), n = 20), roc50 = ROC(Cl(z), n=50))

#> tail(cbind(z, roc20 = ROC(Cl(z), n = 20), roc50 = ROC(Cl(z), n=50)))
#                                  Open   High    Low  Close   Volume      Close.1      Close.2
#2021-Oct-08 00:00:00.000  -0600 439.48 439.89 437.19 437.86 74557404 -0.013933130 -0.003121482
#2021-Oct-11 00:00:00.000  -0600 437.16 440.26 434.62 434.69 65233285 -0.023755219 -0.005519280
#2021-Oct-12 00:00:00.000  -0600 435.67 436.10 432.78 433.62 71181163 -0.020808594 -0.005883621
#2021-Oct-13 00:00:00.000  -0600 434.71 436.05 431.54 435.18 72973979 -0.025535398 -0.010395012
#2021-Oct-14 00:00:00.000  -0600 439.08 442.66 438.58 442.50 70236825 -0.007268168  0.011216814
#2021-Oct-15 00:00:00.000  -0600 444.75 446.26 444.09 445.87 66260210  0.010075936  0.012490885

Desired Results

#                                  Open   High    Low  Close   Volume      roc20      roc50
#2021-Oct-08 00:00:00.000  -0600 439.48 439.89 437.19 437.86 74557404 -0.013933130 -0.003121482
#2021-Oct-11 00:00:00.000  -0600 437.16 440.26 434.62 434.69 65233285 -0.023755219 -0.005519280
#2021-Oct-12 00:00:00.000  -0600 435.67 436.10 432.78 433.62 71181163 -0.020808594 -0.005883621
#2021-Oct-13 00:00:00.000  -0600 434.71 436.05 431.54 435.18 72973979 -0.025535398 -0.010395012
#2021-Oct-14 00:00:00.000  -0600 439.08 442.66 438.58 442.50 70236825 -0.007268168  0.011216814
#2021-Oct-15 00:00:00.000  -0600 444.75 446.26 444.09 445.87 66260210  0.010075936  0.012490885
ethanbsmith commented 2 years ago

the advantage the a deparse solution has is that it would allow me to only rename the things that need it. Also it would get me out of the mess of having to keep track of names by order like my ApplyNames workaround does

joshuaulrich commented 2 years ago

One workaround is to use drop() to remove the dimension (and column name) from the univariate objects you're binding.

cb <-
cbind(z,
      roc20 = drop(ROC(Cl(z), n = 20)),
      roc50 = drop(ROC(Cl(z), n = 50))
)
tail(cb[,-(1:3)])                                                                          
##            SPY.Close SPY.Volume SPY.Adjusted       roc20        roc50
## 2021-10-08    437.86   74492900       437.86 -0.01716337 -0.006351706
## 2021-10-11    434.69   65233300       434.69 -0.02698539 -0.008749501
## 2021-10-12    433.62   71181200       433.62 -0.02403884 -0.009113827
## 2021-10-13    435.18   72974000       435.18 -0.02876563 -0.013625218
## 2021-10-14    442.50   70236800       442.50 -0.01049840  0.007986585
## 2021-10-15    445.87   66226800       445.87  0.01007594  0.009260648

The underlying issue is how merge.xts() handles column names, so it might take some time to get this changed. merge.xts() is central to the entire package's functionality, so we have to be very careful not to break things when making changes.

ethanbsmith commented 2 years ago

thats great! dont know enough about r internals to know why that works. i expect about 90% + of my scenarios are univariate output


From: Joshua Ulrich @.> Sent: Sunday, October 17, 2021 7:29 AM To: joshuaulrich/xts @.> Cc: Ethan Smith @.>; Author @.> Subject: Re: [joshuaulrich/xts] cbind support for deparse.level (#358)

One workaround is to use drop() to remove the dimension (and column name) from the univariate objects you're binding.

The underlying issue is how merge.xts() handles column names, so it might take some time to get this changed. merge.xts() is central to the entire package's functionality, so we have to be very careful not to break things when making changes.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/joshuaulrich/xts/issues/358#issuecomment-945123792, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AF2ACB7KNGSHO733CVKTHMLUHLFUJANCNFSM5FYMITAA. Triage notifications on the go with GitHub Mobile for iOShttps://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Androidhttps://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

ethanbsmith commented 2 years ago

im going to close this issue, as i no longer think xts should handle this differently. in fact, i think drop is probably the correct way to deal with this, rather than having cbind special case a single column matrix