使用predict()函数时出错。

5

我需要将ar.ols的输出转换为predict可以接受的类型吗?

y=rnorm(100, 0,1)
z=rnorm(100, 0,1)
yz=cbind(y,z)
> output = ar.ols(yz, aic = F, order.max = 2, demean = F, intercept = T)    
> predict(output, n.ahead = 2, se.fit = F)

x=as.data.frame(yz) # x is a data frame, and otherwise same as yz. 
> output = ar.ols(x, aic = F, order.max = 2, demean = F, intercept = T)    
> predict(output, n.ahead = 2, se.fit = F)
Error in array(STATS, dims[perm]) : 'dims' cannot be of length 0

谢谢!


有了可重现的例子,寻找问题会更有趣... - DatamineR
@RStudent:谢谢。我按照你的提示操作,问题是因为x是一个数据框。将x替换为as.matrix(x),问题就解决了。我想知道为什么。 - Tim
1
这与predict.ar如何重构提供给ar.ols的数据有关。这段代码对我来说似乎有点奇怪,但我的一般建议是,由于ar.ols的文档说它应该传递一个时间序列,所以你应该传递一个时间序列对象。 - joran
@joran:谢谢!如何将矩阵或数据框转换为时间序列对象? - Tim
1
请参阅?ts。我不认为数据框与时间序列函数兼容。矩阵或时间序列对象是正确的选择。 - joran
@Tim,这个回答解决了你的问题吗?还有什么不清楚的地方吗? - David Arenburg
1个回答

13
因此,错误来自于 predict.ar。如果你运行 ?predict,你会发现它是一个通用函数,"调用依赖于第一个参数的类的特定方法"。
所以,
class(output)
[1] "ar"

并且

methods(predict)
#  [1] predict.ar*                predict.Arima*             predict.arima0*            predict.glm                predict.HoltWinters*      
#  [6] predict.lm                 predict.loess*             predict.mlm*               predict.nls*               predict.poly*             
# [11] predict.ppr*               predict.prcomp*            predict.princomp*          predict.smooth.spline*     predict.smooth.spline.fit*
# [16] predict.StructTS*

#    Non-visible functions are asterisked       

告诉您我们正在寻找第一种方法。
下一步尝试是在该方法中查找错误消息。上一个操作告诉我们predict.ar是不可见函数,因此我们需要结合getAnywherecapture.output以及一些正则表达式函数来查找错误消息,但不幸的是这样做行不通。
grep("array", capture.output(getAnywhere("predict.ar")))
## integer(0)

这意味着错误来自于预测函数predict.ar内部运行的其他函数。

(正如@hadley所提到的)我们需要使用traceback()来识别导致错误的内部函数。

predict(output, n.ahead = 2, se.fit = F)
# Error in array(STATS, dims[perm]) : 'dims' cannot be of length 0
traceback()
# 6: array(STATS, dims[perm])
# 5: aperm(array(STATS, dims[perm]), order(perm))
# 4: sweep(newdata, 2L, object$x.mean, check.margin = FALSE)
# 3: rbind(sweep(newdata, 2L, object$x.mean, check.margin = FALSE), 
#          matrix(rep.int(0, nser), n.ahead, nser, byrow = TRUE))
# 2: predict.ar(output, n.ahead = 2, se.fit = F)
# 1: predict(output, n.ahead = 2, se.fit = F)

这很好地展示了我们的函数调用工作流程: 调用predict -> 识别对象的类并调用相应的方法predict.ar -> 使用sweep将预先分配的矩阵(大小为ncol(x)*n.ahead)与使用均值中心化数据的矩阵rbind -> 在使用sweep进行均值中心化数据时,转置一些array并创建一个新的array,而最后一个操作则返回错误。
所以基本上所有sweep函数所做的就是从yz中减去yz的平均值(即进行均值中心化-可以通过运行scale(yz, scale = FALSE)来完成,因此不确定为什么他们首先使用sweep。也许是为了特殊情况dmean = FALSE?)。在您的情况下,您指定了dmean = FALSE,因此它会从两列中删除零(这是非常不必要的操作,可能应该在这种情况下避免)。比较一下。
all.equal(t(t(yz) - colMeans(yz)), sweep(yz, 2L, colMeans(yz)))
## [1] TRUE

唯一的问题是sweep操作针对的是数组,因此它会尝试将您的数据转换为一个数组,并通过从yz传递dim属性来指定正确的维度,以创建一个array供进一步操作使用,如下:

dims <- dim(yz)
perm <- c(2L, seq_along(dims)[-2L])
array(colMeans(yz), dims[perm])

矩阵非常适合这种操作,因为按定义所有矩阵都有一个“dim”属性。

虽然数据框没有“dim”属性,但“dim(x)”函数仍然足够聪明,可以自己计算“dim”,所以这个方法完全可行。

dim(x)
## [1] 100   2

唯一的问题是,predict.ar函数在到达sweep之前,在某个过程中从x中剥离了class属性,因此这就是matrixdata.frame之间差异的重要性所在。请注意,HTML标签已保留。
class(x) <- NULL
dim(x)
## NULL
class(x)
## [1] "list"

class(yz) <- NULL
dim(yz)
## [1] 100   2
class(yz)
## [1] "matrix"

请注意,x 成为一个包含不同元素(如向量和属性)的 list,而 matrix 保持其原始结构,这要归功于其 dim 属性,因此 class 函数仍然可以识别它是一个矩阵,而 x 则完全变形,class 无法处理它。
如果您想了解 class 的工作原理以及发生了什么,请参见我的回答here 无论如何,虽然这仍然有效。
STATS <- colMeans(yz)
class(yz) <- NULL
dims <- dim(yz)
perm <- c(2L, seq_along(dims)[-2L])
array(STATS, dims[perm])

这会返回之前看到的错误。
x <- as.data.frame(yz)
STATS <- colMeans(x)
class(x) <- NULL
dims <- dim(x)
perm <- c(2L, seq_along(dims)[-2L])
array(STATS, dims[perm])
# Error in array(STATS, dims[perm]) : 'dims' cannot be of length 0

我将让您愉快地深入挖掘兔子洞,以更好地了解dim的工作原理。


因此,在这里总结一下(正如@joran的评论中所提到的)- 请始终先阅读文档。如果您仔细查看?ar.ols,则x应为单变量或多元时间序列。在示例中,x始终是类ts的对象,永远不是data.frame

因此,虽然我同意对于这种特定情况,当您指定demean = FALSE时,此错误本不应发生,但了解自己正在做什么仍然是更好的实践方法。换句话说,这是典型的XY问题类型的问题。


我认为使用traceback()会更快地找到错误源,而不必采用如此复杂的技巧。 - hadley
@hadley 谢谢,已添加。 - David Arenburg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接