stl()分解无法接受单变量时间序列对象?

5
我在使用R中的stl()时间序列分解函数时出现了问题,它告诉我我的ts对象不是单变量,但实际上它是单变量的。
tsData <- ts(data = dummyData, start = c(2012,1), end = c(2014,12), frequency = 12)

> tsData
     Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2012  22  26  34  33  40  39  39  45  50  58  64  78
2013  51  60  80  80  93 100  96 108 111 119 140 164
2014 103 112 154 135 156 170 146 156 166 176 193 204

> class(tsData)
[1] "ts"

> stl(tsData, s.window = "periodic")
Error in stl(tsData, s.window = "periodic") : 
  only univariate series are allowed

> dput(dummyData)
structure(list(index = c(22L, 26L, 34L, 33L, 40L, 39L, 39L, 45L, 
50L, 58L, 64L, 78L, 51L, 60L, 80L, 80L, 93L, 100L, 96L, 108L, 
111L, 119L, 140L, 164L, 103L, 112L, 154L, 135L, 156L, 170L, 146L, 
156L, 166L, 176L, 193L, 204L)), .Names = "index", class = "data.frame", row.names = c(NA, 
-36L))

有人知道如何解决这个问题吗?


我不明白为什么你声称 tsData 是单变量的。它并不是。 - Roland
你的意思是Roland这个变量被转换为时间序列对象了吗? - moku
这个回答解决了你的问题吗?在R中的时间序列和stl:错误只允许单变量系列 - Santiago Capobianco
7个回答

13
为避免此类问题或错误,请尝试通过形成原始数据点或值并调用ts()函数来制作单变量时间序列。更好地说,您应始终只放置变量的值而不是整个变量结构。让我通过一个非常简单的例子来解释一下:假设您有一个变量X,它是一个100x1维向量(很可能是从其他数据源导入或形成的),即它包含100个值或数据点。如果要从此向量制作单变量时间序列,则像您为自己的情况所做的那样错误的方式如下:ts(X, frequency=24)。请注意,正确的方法是这样的:ts(X[1:100], frequency=24),甚至像这样:ts(X[1:100,1], frequency=24)。我希望我的亲爱的朋友们在下次需要制作单变量时间序列时可以避免这种错误..!!

这非常有趣且有帮助。但是如何从要从 csv 文件中读取的列创建 ts?因此,我的 X 是文件的(唯一)列。我是 R 的新手。 - FaCoffee
1
通常你可以在R中使用一些文件读取命令(如read.csvread.csv2或者read.delim)来从该文件创建数据框。然后你可以使用所创建的数据帧的数值或内容(例如,如果第一列或单个列被命名为“x1”,则通过写入X$x1[1:100])使用ts()命令将其转换为单变量时间序列。 - Elias
1
Urgh. ts(X, frequency=24) 肯定不应该是这样做的“错误”方式。ts 的设计很差。 - Nick

5

我不完全确定问题的确切原因,但您可以通过将dummyData$index传递给ts而不是整个对象来解决此问题:

tsData2 <- ts(
  data=dummyData$index, 
  start = c(2012,1), 
  end = c(2014,12), 
  frequency = 12)
##
R>  stl(tsData2, s.window="periodic")
 Call:
 stl(x = tsData2, s.window = "periodic")

Components
            seasonal     trend   remainder
Jan 2012 -24.0219753  36.19189   9.8300831
Feb 2012 -20.2516062  37.82808   8.4235219
Mar 2012  -0.4812396  39.46428  -4.9830367
Apr 2012 -10.1034302  41.32047   1.7829612
May 2012   0.6077088  43.17666  -3.7843705
Jun 2012   4.4723800  45.22411 -10.6964877
Jul 2012  -7.6629462  47.27155  -0.6086074
Aug 2012  -1.0551286  49.50673  -3.4516016
Sep 2012   2.2193527  51.74191  -3.9612597
Oct 2012   7.3239448  55.27391  -4.5978509
Nov 2012  18.4285405  58.80591 -13.2344456
Dec 2012  30.5244146  63.70105 -16.2254684

我猜当你将data.frame传递给tsdata参数时,一些额外属性会被传递过去,尽管这通常对于许多接受ts类对象(单变量或其他) 的函数似乎并不是一个问题,但显然对于stl来说确实是个问题。

R>  all.equal(tsData2,tsData)
[1] "Attributes: < Names: 1 string mismatch >"                         
[2] "Attributes: < Length mismatch: comparison on first 2 components >"
[3] "Attributes: < Component 2: Numeric: lengths (3, 2) differ >"      
##
R>  str(tsData2)
 Time-Series [1:36] from 2012 to 2015: 22 26 34 33 40 39 39 45 50 58 ...
##
R>  str(tsData)
 'ts' int [1:36, 1] 22 26 34 33 40 39 39 45 50 58 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr "index"
 - attr(*, "tsp")= num [1:3] 2012 2015 12

编辑:

进一步研究后,我认为问题与dummyData作为整体传递时携带的dimnames属性有关。请注意以下来自stl主体的摘录:

if (is.matrix(x)) 
        stop("only univariate series are allowed")

根据矩阵的定义:

如果x是一个向量并且有一个长度为2的“dim”属性,则is.matrix返回TRUE,否则返回FALSE。

因此,虽然你将原始的tsData作为单变量时间序列传递给了stl函数,但对于该函数而言,带有长度为2的dimnames属性的向量(即一个matrix不是单变量序列。这种方式进行错误处理似乎有点奇怪,但我相信函数的作者一定有很好的理由。


2
另一种解决时间序列数据问题的方法是:
stl(tsData[, 1], s.window = "periodic")

请进行比较。
str(tsData)

使用

str(tsData[, 1])

查看差异。


1
我遇到了同样的问题,以下是我解决的方法:
stl(x[,1], s.window = "periodic")

在我遇到的所有解决方法中,这是唯一一个有效的方法。删除属性无法解决问题。从ts到vector再返回也不行。即使 obj obj[,1] 全为 TRUE 。难以言喻。 - Richard Careaga

0
问题可能是你没有指定end = c(yyyy,mm)。
如果你正在使用decompose,你不需要指定end =。如果你切换到stl并使用一些旧代码,你需要添加这个参数(如果你在decompose中没有使用它)。
这个方法解决了我遇到的“单变量”错误问题。

0
当一个数据框对象被传递给ts()函数时,它将通过data.matrix()(参见help(ts))被强制转换为数字矩阵。 ts()函数将返回一个时间序列对象,它将是一个类为“ts”的矩阵,并带有一个新属性“tsp”和原始数据框属性。这些最后会被转换为'dimnames'作为两个属性(dimnames[[1]](原来是“row.names”)和dimnames[[2]](原来是“names”)的列表。
当一个向量被传递给ts()时,它将返回一个由向量和“tsp”属性组成的时间序列对象。
最后,当一个时间序列对象被传递给stl()时,它将通过is.matrix()检查对象是否为矩阵,如果是,则返回错误。
if (is.matrix(x)) 
      stop("only univariate series are allowed")

注意:

  • 数据框是一个等长向量列表,具有“names”和“row.names”等属性。
  • “时间序列对象是一个带有类'ts'和其他属性的向量或矩阵”(help(ts))。

要检查R对象属性,请调用函数:attributes(obj) 还可以使用函数is.vector(obj)dim(obj)dimnames(obj)验证对象的维度,即它是否为向量。

以下是示例代码:

# Exploring stl() arguments #

# load packages ####
if (!require("pacman")) install.packages("pacman")
pacman::p_load("vctrs")
pacman::p_load("stats")

# create a data frame "df" ####
df <- vctrs::data_frame(x = 133:165, y = pi, z = seq(25.25, 1.25, by = -0.75))

# visualizing and checking attributes
head(df)
str(df)
attributes(df)
dimnames(df)

# accessing single vectors/variables with subsetting ####
# 1 - double brackets
head(df[[3]]) # return a vector
is.vector(df[[3]])
# 2 - $ operator
head(df$z) # returns a vector
is.vector(df$z)
# 3 - single brackets 
head(df[3]) # return a data frame!
is.vector(df[3])
dim(df[3])
dimnames(df[3])
attributes(df[3])

# creating a Time-Series object using ts() ####
MySeriesTs1 <- ts(df[[3]], start = c(1999, 10), frequency = 12)
MySeriesTs1
str(MySeriesTs1)
dim(MySeriesTs1) # time-series is a vector

MySeriesTs2 <- ts(df$z, start = c(1999, 10), frequency = 12)
MySeriesTs2
str(MySeriesTs2)
dim(MySeriesTs2) # time-series is a vector

MySeriesTs3 <- ts(df[3], start = c(1999, 10), frequency = 12)
MySeriesTs3
str(MySeriesTs3)
dim(MySeriesTs3) # time-series is a matrix!
dimnames(MySeriesTs3)
attributes(MySeriesTs3)

# Note: ts() accepts either a vector, a matrix or a data frame object as argument.
# here I pass the data frame with all three variables as argument to ts()
MySeriesTs <- ts(df, start = c(1999, 10), frequency = 12)
MySeriesTs
dim(MySeriesTs)
str(MySeriesTs) #returns a matrix with a List of 2 "dimnames" attributes: NULL and "x" "y" "z"

# calling stl() function ####
# stl() accepts only univariate time series as argument.
# Therefore, if the Time-Series object is a matrix, it has to be subset when passed to stl.
# passing a vector
MyDecompose1 <- stl(MySeriesTs1, s.window = 'p') # RUN
# passing a vector
MyDecompose2 <- stl(MySeriesTs2, s.window = 'p') # RUN
# passing a matrix
MyDecompose3 <- stl(MySeriesTs3, s.window = 'p') # ERROR!
# passing a subset of a matrix
MyDecompose3 <- stl(MySeriesTs3[,"z"], s.window = 'p') # RUN
# passing a matrix
MyDecompose <- stl(MySeriesTs, s.window = 'p') #ERROR!
# passing a subset of a matrix
MyDecompose <- stl(MySeriesTs[,"z"], s.window = 'p') #RUN

0

我有同样的错误,正如nrussell所提到的,问题是我传递了一个既是时间序列又是矩阵的对象。

(然而,$index 对我没有用,R 抱怨 ts 对象必须要有一个或多个观测值。我对 R 还很新,不知道这是为什么,但是对我来说以下方法可行)

您可以通过以下方法解决这个问题:

dummyVector = as.vector(t(dummyData))

然后继续获取STL:

tsData = ts(dummyVector, start=2012, end=(2014, 12), frequency = 12)
stl = stl(tsData, "periodic")

如果你使用R Studio,你会发现现在你的时间序列被列在下面:

时间序列 [1:36] 从2012年到2015年:yourData

而之前,它可能被列为:

int[1:3, 1:12] yourData


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