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
219 stars 71 forks source link

zero-length versus zero-width #168

Open joshuaulrich opened 7 years ago

joshuaulrich commented 7 years ago

It's quite common to create a zero-width xts object for aligning series or making irregular series regular. A zero-width xts object has an index, but no data.

# zero-width xts object
R> xts(, as.Date("2017-01-01") + 0:9)
Data:
numeric(0)

Index:
 Date[1:11], format: "2017-01-01" "2017-01-02" "2017-01-03" "2017-01-04" ...
R> str(xts(, as.Date("2017-01-01") + 0:9))
An 'xts' object of zero-width

But you can also create a "zero-length" xts object by subsetting outside the bounds of the index. For example:

R> x <- xts(1:10, as.Date("2017-01-01") + 0:9)
R> x["1900"]
     [,1]
R> str(x["1900"])
An 'xts' object of zero-width
R> unclass(x["1900"])
     [,1]
attr(,".indexCLASS")
[1] "Date"
attr(,"tclass")
[1] "Date"
attr(,".indexTZ")
[1] "UTC"
attr(,"tzone")
[1] "UTC"
attr(,"index")
numeric(0)
attr(,"index")attr(,"tzone")
[1] "UTC"
attr(,"index")attr(,"tclass")
[1] "Date"
R> dim(x["1900"])
[1] 0 1

Note that str(x["1900"]) returns "An 'xts' object of zero-width", which isn't true. As you can see from dim(x["1900"]), the "width" is 1 but there are no rows. So I would call x["1900"] a "zero-length xts object". It's not clear to me if/how these should be supported by other functions (e.g. merge), but at minimum str shouldn't say they're zero-width xts objects.

steve4444 commented 7 years ago

I think that zero-row/length objects are useful when you want to model available observations in a given time frame and no observations are available for some securities. Apart from this, one could rule out them, like a division-by-zero error, but since they are currently legal objects, merge.xts should support them. Also because, given a zero-length x, it seems quite natural to set to NA x column(s) in merge(x,y, all=TRUE) and to output another zero-length xts, from merge(x,y, all=FALSE)

steve4444 commented 7 years ago

Another function that should be fixed for zero objects is names():

e <- xts(data.frame(p=numeric()), as.Date(character()))
names(e)
# NULL

The result should be "p". Also, off topic a bit, but speaking of names:

(x <- xts(data.frame(p=1), as.Date(1)))
#            p
# 1970-01-02 1

(y <- xts(c(p=1), as.Date(1)))
#            [,1]
# 1970-01-02    1

could/should both name the column p.

joshuaulrich commented 7 years ago

Thanks for the feedback, @steven001.

There is no names.xts() method, so the names.zoo() method is being called. And it looks like xts behaves the same as zoo in this case.

require(xts)
x1 <- .xts(data.frame(a=1, b=1), 1)
z1 <- as.zoo(x1)
x0 <- .xts(data.frame(a=numeric(), b=numeric()), numeric())
z0 <- as.zoo(x0)
names(x1) # [1] "a" "b"
names(z1) # [1] "a" "b"
names(x0) # NULL
names(z0) # NULL

In your second example, c(p=1) is a named vector; and vectors are column-wise in R, so the names would be row names. That means your y object should not have column names.