`sapply`是成功的#34;动物园"对象但不是" xts"对象,为什么?

时间:2016-09-29 18:41:46

标签: r dataframe xts zoo sapply

这是一个显示"动物园"之间明显区别的例子。和" 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

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

1 个答案:

答案 0 :(得分:3)

我认为你提出了一个非常好的问题。在做出回答之前,我想评论你可以使用

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
啊,对于&#34;动物园&#34;对象,维度被删除所以我们得到一个向量;而对于&#34; xts&#34;对象,维度不会被删除因此我们得到一个列矩阵!

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

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

  1. sapply(myzoo, "+", 1, simplify = "array")给出一个2D数组(即你看到的矩阵);
  2. sapply(myxts, "+", 1, simplify = "array")提供 3D阵列
  3. 从这个例子中,我们可以看出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(y1)
    # [1] "zoo"
    
    class(y2)
    # [1] "xts" "zoo"
    

    <强>后续

      

    出于好奇...... *apply家庭的功能是否等同于您的两步程序(即lapply + do.call)?

    似乎没有。您可以从?lapply获取所有这些内容(包括&#34;另请参阅&#34;部分)。如果确实如此,此网站上的用户不会经常lapply + do.call组合。