`sapply` 对 "zoo" 对象成功但对 "xts" 对象不成功,为什么?

`sapply` is successful for "zoo" object but not "xts" object, why?

这是一个显示 "zoo" 和 "xts" 之间明显区别的示例。

library(xts)

mydf = as.data.frame(replicate(6, sample(c(1:10), 10, rep = T)))
myzoo = zoo(mydf, order.by = Sys.Date() + 1:10)
resultzoo = sapply(myzoo, function(x) x+1)

虽然我丢失了日期(这是已经评论过的行为 here),但上面的代码工作正常。但是,下面的代码给出了错误

myxts = xts(mydf, order.by = Sys.Date() + 1:10)
resultxts = sapply(myxts, function(x) x+1)
# Error in array(r, dim = d, dimnames = if (!(is.null(n1 <- names(x[[1L]])) &  : 
# length of 'dimnames' [1] not equal to array extent

我找不到对这种奇怪行为的任何解释。欢迎任何想法。

我觉得你提出了一个很好的问题。在回答之前,我想评论一下你可以使用

sapply(myzoo, "+", 1)
sapply(myxts, "+", 1)

而不是

sapply(myzoo, function (x) x + 1)
sapply(myxts, function (x) x + 1)

这是因为 "+" 已经是一个函数。试试 1 + 2"+"(1, 2).


sapply 需要两个阶段。第一阶段是对 lapply 的普通调用;第二阶段是调用 simplify2array 来简化结果。您收到的错误消息表明在第二阶段发生了错误。事实上,如果我们尝试:

x1 <- lapply(myzoo, "+", 1)
x2 <- lapply(myxts, "+", 1)

我们完全没有错误!

但是,如果我们比较 x1x2,我们就会看到不同之处。为了整洁起见,我只提取第一个列表元素:

x1[[1]]

#2016-09-30 2016-10-01 2016-10-02 2016-10-03 2016-10-04 2016-10-05 2016-10-06 
#         3          4          5          7          2          2          4 
#2016-10-07 2016-10-08 2016-10-09 
#         3          5          3 

x2[[1]]

#           V1
#2016-09-30  3
#2016-10-01  4
#2016-10-02  5
#2016-10-03  7
#2016-10-04  2
#2016-10-05  2
#2016-10-06  4
#2016-10-07  3
#2016-10-08  5
#2016-10-09  3

啊,对于 "zoo" 对象,降维了所以我们得到了一个向量;而对于 "xts" 对象,维度没有下降,因此我们得到一个单列矩阵!

正是由于这个原因,sapply 失败了。默认情况下,sapply 的简化选项是 simplify = TRUE,它总是尝试简化为一维向量或二维矩阵。对于x1,这没有问题;但对于 x2,这是不可能的。

如果我们使用更温和的设置:simplify = "array",我们将得到适当的行为:

  1. sapply(myzoo, "+", 1, simplify = "array")给出一个二维数组(即你看到的矩阵);
  2. sapply(myxts, "+", 1, simplify = "array") 给出一个 3D 数组.

从这个例子中,我们可以看出 sapply 并不总是可取的。为什么不使用以下内容:

y1 <- do.call(cbind, x1)
y2 <- do.call(cbind, x2)

#           V1 V2 V3 V4 V5 V6
#2016-09-30  3  8  6  4 11  3
#2016-10-01  4  3  9  2  5  7
#2016-10-02  5  7  9  7  7 10
#2016-10-03  7  2  5  3  5  3
#2016-10-04  2  6  7  2  4  5
#2016-10-05  2  2 11  2  4  7
#2016-10-06  4  3 10 10  8  2
#2016-10-07  3  6  4  5  9  4
#2016-10-08  5  4 10 10  3  8
#2016-10-09  3  3 11  8 11  7

它们给出相同的输出,而且您得到的是日期作为行名!更有什者,原物class为尊!

class(y1)
# [1] "zoo"

class(y2)
# [1] "xts" "zoo"

跟进

Out of curiosity....is there a function for the *apply family doing the equivalent of your two step procedure (i.e. lapply + do.call)?

好像不是。您可以从 ?lapply 获取所有这些(包括 "See Also" 部分)。如果真的有,这个网站上的人就不会经常做 lapply + do.call 组合了。