【问题标题】:How to merge xts objects with slightly different columns?如何将 xts 对象与稍微不同的列合并?
【发布时间】:2016-01-03 17:44:56
【问题描述】:

给定各种单行 xts 对象:

z1 = xts(t(c("9902"=0,"9903"=0,"9904"=0,"9905"=2,"9906"=2)),as.Date("2015-01-01"))
z2 = xts(t(c("9902"=3,"9903"=4,"9905"=6,"9906"=5,"9908"=8)),as.Date("2015-01-02"))
z3 = xts(t(c("9901"=1,"9903"=3,"9905"=5,"9906"=6,"9907"=7,"9909"=9)),as.Date("2015-01-03"))

我想将它们合并成一个 xts 对象。但是cbind(z1,z2,z3) 给出:

           X9902 X9903 X9904 X9905 X9906 X9902.1 X9903.1 X9905.1 X9906.1 X9908 X9901 X9903.2 X9905.2 X9906.2 X9907 X9909
2015-01-01     0     0     0     2     2      NA      NA      NA      NA    NA    NA      NA      NA      NA    NA    NA
2015-01-02    NA    NA    NA    NA    NA       3       4       6       5     8    NA      NA      NA      NA    NA    NA
2015-01-03    NA    NA    NA    NA    NA      NA      NA      NA      NA    NA     1       3       5       6     7     9

而我的期望是:

           9901 9902 9903 9904 9905 9906 9907 9908 9909
2015-01-01    0    0    0    0    2    2    0    0    0
2015-01-02    0    3    4    0    6    5    0    8    0
2015-01-03    1    0    3    0    5    6    7    0    9

(我可以通过提供fill=0 将NA 更改为零,即cbind(z1,z2,z3,fill=0)。)

rbind(z1,z2,z3) 抱怨行有不同的列数。但是,我相信如果预先将丢失的列添加到每个 xts 对象中,这将是一个好方法吗?

真实数据可能有 1000 行,几百列(一旦合并),所以我只关注效率。

【问题讨论】:

  • merge.xtsmerge.zoo 仅按索引合并,因此使用 merge(或 cbind)无法获得所需的结果。所以看起来你确实需要rbind,但是(正如你所说)它将要求所有对象都具有相同数量的列以相同的顺序。

标签: r xts


【解决方案1】:

正如我在评论中提到的,merge.xts(和merge.zoo)仅按索引合并,因此使用merge(或cbind)无法获得所需的结果。所以看起来你确实需要rbind,但是(正如你所说)它将要求所有对象都具有相同数量的列以相同的顺序。

我在下面创建了两个函数来帮助处理对象,以便您可以rbind 它们来创建您想要的结果。

# put all xts objects in a list for easier processing
x <- list(z1, z2, z3)

# function to create template xts object
template <- function(xlist) {
  # find set of unique column names from all objects
  cn <- unique(unlist(lapply(xlist, colnames)))
  # create template xts object
  # using a date that doesn't occur in the actual data
  minIndex <- do.call(min, lapply(xlist, function(x) index(x[1L,])))
  # template object
  xts(matrix(0,1,length(cn)), minIndex-1, dimnames=list(NULL, sort(cn)))
}

# function to apply to each xts object
proc <- function(x, template) {
  # columns we need to add
  neededCols <- !(colnames(template) %in% colnames(x))
  # merge this object with template object, filling w/zeros
  out <- merge(x, template[,neededCols], fill=0)
  # reorder columns (NB: merge.xts always uses make.names)
  # and remove first row (from template)
  out <- out[-1L,make.names(colnames(template))]
  # set column names back to desired values
  # (using attr<- because dimnames<-.xts copies)
  attr(out, "dimnames") <- list(NULL, colnames(template))
  # return object
  out
}
(res <- do.call(rbind, lapply(x, proc, template=template(x))))
#            9901 9902 9903 9904 9905 9906 9907 9908 9909
# 2015-01-01    0    0    0    0    2    2    0    0    0
# 2015-01-02    0    3    4    0    6    5    0    8    0
# 2015-01-03    1    0    3    0    5    6    7    0    9

【讨论】:

  • 谢谢;我想我会同意的。与重新制作每个 xts 对象然后调用 rbind 相比,您是否认为预先制作一个巨大的空矩阵并将其复制到其中会有显着的性能差异? (由于 R 中的矩阵是按列排序的,所以我认为 rbind 需要进行这种复制,无论如何?)
  • @DarrenCook:我没想到。它可能更快,但我必须分析以验证任何一种方式。 rbind 确实会进行这种复制,但它可以使用 memcopy,这通常比调用 R 函数更快。
【解决方案2】:
library(xts)
library(plyr)

z1df <- as.data.frame(z1)
z2df <- as.data.frame(z2)
z3df <- as.data.frame(z3)

res <- rbind.fill(z1df, z2df, z3df)
res[is.na(res)] <- 0
res

#  9902 9903 9904 9905 9906 9908 9901 9907 9909
#1    0    0    0    2    2    0    0    0    0
#2    3    4    0    6    5    8    0    0    0
#3    0    3    0    5    6    0    1    7    9

这类似于下面的stackoverflow帖子

combining two data frames of different lengths

包括日期列

res$Date <- c("2015-01-01", "2015-01-02", "2015-01-03") # the appropriate values
res$Date <- as.Date(res$Date)

并转换为 xts 对象

xts(res[,-10], order.by=res[,10])

【讨论】:

  • rbind.fill 不在 xts 中。您的结果也不是 xts 对象。
  • @JoshuaUlrich 谢谢。
  • 更新后的解决方案假定每个对象中的时间是连续且不重叠的,但情况可能并非如此。应用于实际数据,它可能会为每一行分配错误的日期。
  • 谢谢;一个有趣的方法。 (顺便说一句,在我的情况下,日期列将是不重叠的,并且可以按顺序排列。)
猜你喜欢
  • 2021-11-23
  • 2020-11-06
  • 1970-01-01
  • 2022-01-25
  • 2016-11-09
  • 1970-01-01
  • 2018-06-04
  • 2016-12-13
  • 2018-09-13
相关资源
最近更新 更多