如何让 highcharter 代表预测对象?

How can I get highcharter to represent a forecast object?

这是 的后续。

我正在尝试让该问题中给出的管道接受预测对象作为输入:

再次使用此数据:

> dput(t)
structure(c(2, 2, 267822980, 325286564, 66697091, 239352431, 
94380295, 1, 126621669, 158555699, 32951026, 23, 108000151, 132505189, 
29587564, 120381505, 25106680, 117506099, 22868767, 115940080, 
22878163, 119286731, 22881061), .Dim = c(23L, 1L), index = structure(c(1490990400, 
1490994000, 1490997600, 1491001200, 1491004800, 1491008400, 1491012000, 
1491026400, 1491033600, 1491037200, 1491040800, 1491058800, 1491062400, 
1491066000, 1491069600, 1491073200, 1491076800, 1491109200, 1491112800, 
1491120000, 1491123600, 1491156000, 1491159600), tzone = "US/Mountain", tclass = c("POSIXct", 
"POSIXt")), class = c("xts", "zoo"), .indexCLASS = c("POSIXct", 
"POSIXt"), tclass = c("POSIXct", "POSIXt"), .indexTZ = "US/Mountain", tzone = "US/Mountain", .CLASS = "double", .Dimnames = list(
    NULL, "count"))

我用

highchart(type = 'stock') %>% 
    hc_add_series(t) %>% 
    hc_xAxis(type = 'datetime')

创建

但是如果我按照同样的食谱使用

require("forecast")
t.arima <- auto.arima(t)
x <- forecast(t.arima, level = c(95, 80))

highchart(type = 'stock') %>% 
     hc_add_series(x) %>%
     hc_xAxis(type = 'datetime')

我收到这个错误:

Error in as.Date.ts(.) : unable to convert ts time to Date class

如何将预测系列与历史系列一起显示?我在文档中看到过这个,但不明白为什么我会收到这个错误。

JK 的 JS 控制台输出: 重新索引后的 DF 数据:

dput(df)
structure(list(Index = structure(c(1490968800, 1490972400, 1490976000, 
1490979600, 1490983200, 1490986800, 1490990400, 1491004800, 1491012000, 
1491015600, 1491019200, 1491037200, 1491040800, 1491044400, 1491048000, 
1491051600, 1491055200, 1491087600, 1491091200, 1491098400, 1491102000, 
1491134400, 1491138000, 1491217200, 1491220800, 1491224400, 1491228000, 
1491231600, 1491235200, 1491238800, 1491242400, 1491246000, 1491249600, 
1491253200, 1491256800, 1491260400, 1491264000, 1491267600), class = c("POSIXct", 
"POSIXt")), Data = c(2, 2, 259465771, 315866206, 64582553, 233440220, 
91918347, 1, 126563786, 158555699, 32951026, 23, 108000151, 132505189, 
29587564, 120381505, 25106680, 117506099, 22868767, 115898351, 
22878163, 119285747, 22881061, 157925588, 32447780, 223096830, 
281656273, 45406684, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), 
    Fitted = c(102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), 
    `Point Forecast` = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143, 102170573.857143, 
    102170573.857143, 102170573.857143, 102170573.857143), `Lo 80` = c(NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -16003477.5789723, 
    -16003477.5789723, -16003477.5789723, -16003477.5789723, 
    -16003477.5789723, -16003477.5789723, -16003477.5789723, 
    -16003477.5789723, -16003477.5789723, -16003477.5789723), 
    `Hi 80` = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, 220344625.293258, 220344625.293258, 220344625.293258, 
    220344625.293258, 220344625.293258, 220344625.293258, 220344625.293258, 
    220344625.293258, 220344625.293258, 220344625.293258), `Lo 95` = c(NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, -78561041.5917782, 
    -78561041.5917782, -78561041.5917782, -78561041.5917782, 
    -78561041.5917782, -78561041.5917782, -78561041.5917782, 
    -78561041.5917782, -78561041.5917782, -78561041.5917782), 
    `Hi 95` = c(NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
    NA, 282902189.306064, 282902189.306064, 282902189.306064, 
    282902189.306064, 282902189.306064, 282902189.306064, 282902189.306064, 
    282902189.306064, 282902189.306064, 282902189.306064)), .Names = c("Index", 
"Data", "Fitted", "Point Forecast", "Lo 80", "Hi 80", "Lo 95", 
"Hi 95"), row.names = c(NA, -38L), class = "data.frame")

不确定这是因为时间序列不规则。

总之,ggfortify:::fortify.forecast是你的朋友。为什么?因为 fortify(尝试)转换数据框中的所有 R 对象。所以:

library(highcharter)
library(forecast)
t.arima <- auto.arima(t)
x <- forecast(t, level = c(95, 80))

library(highcharter)
library(ggplot2)
library(ggfortify)
#> 
#> Attaching package: 'ggfortify'
#> The following object is masked from 'package:forecast':
#> 
#>     gglagplot
class(x)
#> [1] "forecast"

df <- fortify(x)
head(df)
#>   Index      Data    Fitted Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
#> 1     1         2 140658844             NA    NA    NA    NA    NA
#> 2  3601         2 121734145             NA    NA    NA    NA    NA
#> 3  7201 267822980 105355638             NA    NA    NA    NA    NA
#> 4 10801 325286564 127214522             NA    NA    NA    NA    NA
#> 5 14401  66697091 153863779             NA    NA    NA    NA    NA
#> 6 18001 239352431 142136089             NA    NA    NA    NA    NA

现在您可以:

highchart(type = "stock") %>% 
  hc_add_series(df, "line", hcaes(Index, Data), name = "Original") %>% 
  hc_add_series(df, "line", hcaes(Index, Fitted), name = "Fitted") %>%
  hc_add_series(df, "line", hcaes(Index, `Point Forecast`), name = "Forecast") %>% 
  hc_add_series(df, "arearange", hcaes(Index, low = `Lo 80`, high = `Hi 80`), name = "Interval") 

如您所见,fortify也检测不到实时。所以你需要在你想要的时候转换索引。

错误

Error in as.Date.ts(.) : unable to convert ts time to Date class

是因为你有一个频率未被函数覆盖的ts对象as.Date.ts(.)。当我们看到这个函数做了什么时,这就是我们得到的:

function (x, offset = 0, ...) 
{
    time.x <- unclass(time(x)) + offset
    if (frequency(x) == 1) 
        as.Date(paste(time.x, 1, 1, sep = "-"))
    else if (frequency(x) == 4) 
        as.Date(paste((time.x + 0.001)%/%1, 3 * (cycle(x) - 1) + 
            1, 1, sep = "-"))
    else if (frequency(x) == 12) 
        as.Date(paste((time.x + 0.001)%/%1, cycle(x), 1, sep = "-"))
    else stop("unable to convert ts time to Date class")
}

此函数仅考虑 ts 对象的频率的 3 个值:1、4 或 12。当我们查看您的对象的频率 x 时,我们发现它 frequency = 0.000277777777777778,所以当 highcharter 使用 x 中的 ts 对象调用函数时,它会停止并给你那个错误。

关于如何 "fix" 我们有两个选择:

  1. frequency = 1before运行auto.arimat转换为ts对象(而不是xts对象)和forecast;
  2. 经过运行auto.arimaforecast之后,我们可以为未来的日期创建一个索引,并转换[=中的ts对象15=] 到具有正确索引的 xts 对象中。

我说 "fix" 因为这些解决方案并不完美,我们将看到。

选项 1

t <- structure(
  c(2, 2, 267822980, 325286564, 66697091, 239352431,
    94380295, 1, 126621669, 158555699, 32951026, 23, 
    108000151, 132505189, 29587564, 120381505, 25106680,
    117506099, 22868767, 115940080, 22878163, 119286731, 
    22881061), 
  .Dim = c(23L, 1L), 
  index = structure(c(1490990400, 1490994000, 1490997600, 
                      1491001200, 1491004800, 1491008400, 
                      1491012000, 1491026400, 1491033600, 
                      1491037200, 1491040800, 1491058800, 
                      1491062400, 1491066000, 1491069600, 
                      1491073200, 1491076800, 1491109200, 
                      1491112800, 1491120000, 1491123600, 
                      1491156000, 1491159600), 
                    tzone = "US/Mountain", 
                    tclass = c("POSIXct","POSIXt")), 
  class = c("xts", "zoo"), 
  .indexCLASS = c("POSIXct","POSIXt"), 
  tclass = c("POSIXct", "POSIXt"), 
  .indexTZ = "US/Mountain", 
  tzone = "US/Mountain", 
  .CLASS = "double", 
  .Dimnames = list(NULL, "count"))


require("forecast")
library(highcharter)


# SOLUTION 1
t.tmp <- ts(t, start=1, end = length(t))
t.arima.1 <- auto.arima(t.tmp)
x.1 <- forecast(t.arima.1, level = c(95, 80))

highchart(type = 'stock') %>% 
  hc_add_series(x.1) %>%
  hc_add_series(x.1$x, name = "Original") %>% 
  hc_add_series(x.1$fitted, name = "Fitted")

这种方法的问题是我们丢失了日期(轴、工具​​提示等)。

选项 2,第一次尝试:每小时预报

我试图为未来值创建一个小时索引,但出于某种原因,Highcharter 将间隔向左移动(或者日期存在一些问题,我无法 see/figure 出来)。

选项 2,第二次尝试:每日预报

当我将其更改为未来值的每日指数时,它起作用了,但这很奇怪,因为我们有每小时的观察结果,并且我们的图表的预测部分显示 "daily forecasts"。

完整代码如下:

t <- structure(
  c(2, 2, 267822980, 325286564, 66697091, 239352431,
    94380295, 1, 126621669, 158555699, 32951026, 23, 
    108000151, 132505189, 29587564, 120381505, 25106680,
    117506099, 22868767, 115940080, 22878163, 119286731, 
    22881061), 
  .Dim = c(23L, 1L), 
  index = structure(c(1490990400, 1490994000, 1490997600, 
                      1491001200, 1491004800, 1491008400, 
                      1491012000, 1491026400, 1491033600, 
                      1491037200, 1491040800, 1491058800, 
                      1491062400, 1491066000, 1491069600, 
                      1491073200, 1491076800, 1491109200, 
                      1491112800, 1491120000, 1491123600, 
                      1491156000, 1491159600), 
                    tzone = "US/Mountain", 
                    tclass = c("POSIXct","POSIXt")), 
  class = c("xts", "zoo"), 
  .indexCLASS = c("POSIXct","POSIXt"), 
  tclass = c("POSIXct", "POSIXt"), 
  .indexTZ = "US/Mountain", 
  tzone = "US/Mountain", 
  .CLASS = "double", 
  .Dimnames = list(NULL, "count"))

require("forecast")
library(highcharter)
library(xts)

t.arima <- auto.arima(t)
x <- forecast(t.arima, level = c(95, 80))

# Problem 

## Time from 'forecast'
time.x <- time(x$mean) # ts variable
time.x # see that frequency = 0.000277777777777778

## Original time
time.t <- time(t) # POSIXct variable, use as.ts to see frequency
as.ts(time.t) # frequency = 1

## Try to transform back to formatted date
as.POSIXct(as.double(time.t), tz = "US/Mountain", origin = "1970-01-01")
as.POSIXct(as.double(time.x), tz = "US/Mountain", origin = "1970-01-01")

#--------------------------------------------------------#

# SOLUTION 1
t.tmp <- ts(t, start=1, end = length(t))
t.arima.1 <- auto.arima(t.tmp)
x.1 <- forecast(t.arima.1, level = c(95, 80))

highchart(type = 'stock') %>% 
  hc_add_series(x.1) %>%
  hc_add_series(x.1$x, name = "Original") %>% 
  hc_add_series(x.1$fitted, name = "Fitted")

#------------------------------------------------------#

# SOLUTION 2 - With correct dates but wrong plot

## Create new forecast variable
x.2 <- forecast(t.arima.1, level = c(95, 80))

## Take forecast length
forecast.length <- length(time.x)

### Create New Forecast dates (HOUR)
### Since I don't know the exact forecast times, I'll add one HOUR
### for each obs starting from the last date in the original dataset 

last.date <- time.t[length(time.t)]

new.forecast.time.hour <- as.POSIXct(last.date) + c((1:forecast.length)*3600)

## Insert date back

x.2$mean  <- xts(x.1$mean, order.by = new.forecast.time.hour)
x.2$lower <- xts(x.1$lower, order.by = new.forecast.time.hour)
x.2$upper <- xts(x.1$upper, order.by = new.forecast.time.hour)

### Original Data
x.2$x <- xts(x.1$x, order.by = time.t)

### Fitted
x.2$fitted <- xts(x.1$fitted, order.by = time.t)

# Plot forecasts with correct date

highchart(type = 'stock') %>% 
  hc_add_series(x.2) %>%
  hc_add_series(x.2$x, name = "Original") %>% 
  hc_add_series(x.2$fitted, name = "Fitted") %>%
  hc_xAxis(type = 'datetime')

#------------------------------------------------------#

# SOLUTION 3 - Correct plot but only for daily forecasts

## Create new forecast variable
x.3 <- forecast(t.arima.1, level = c(95, 80))

## Take forecast length
forecast.length <- length(time.x)

### Create New Forecast dates (DAY)
### Since I don't know the exact forecast times, I'll add one DAY
### for each obs starting from the last date in the original dataset 

last.date <- time.t[length(time.t)]

new.forecast.time.day <- as.POSIXct(last.date) + c((1:forecast.length)*3600*24)
## Add change from as.POSIXct to as.Date
new.forecast.time.day <- as.Date(new.forecast.time.day)

## Insert date back

x.3$mean  <- xts(x.1$mean, order.by = new.forecast.time.day)
x.3$lower <- xts(x.1$lower, order.by = new.forecast.time.day)
x.3$upper <- xts(x.1$upper, order.by = new.forecast.time.day)

### Original Data
x.3$x <- xts(x.1$x, order.by = time.t)

### Fitted
x.3$fitted <- xts(x.1$fitted, order.by = time.t)

# Plot forecasts with correct date

highchart(type = 'stock') %>% 
  hc_add_series(x.3) %>%
  hc_add_series(x.3$x, name = "Original") %>% 
  hc_add_series(x.3$fitted, name = "Fitted") %>%
  hc_xAxis(type = 'datetime')

另外一件事:我的图上的拟合值与 jbkunst 的图上的拟合值不同,因为他直接在 t 上使用了 forecast,而不是在 t.arima 上(我相信只是一个错字)。这样,我的预测是基于 Arima 模型,而他的预测是基于 ETS 模型。