我一直在使用R中的hmmTMB包,使用隐马尔可夫模型(HMM)对油价走势进行建模和预测.在用训练数据对模型进行拟合后,我很难在测试数据集上使用拟合的模型对观察到的状态(例如油价)做出提前一步的预测.

# Load necessary libraries
library(hmmTMB)
library(tidyverse)

# Set seed for reproducibility
set.seed(123)

# Example dataset preparation (extended for 1 year)
df <- data.frame(
    day = seq.Date(from = as.Date("2020-01-01"), to = as.Date("2020-12-31"), by = "day"),
    OILPRICE = rnorm(366, 100, 10)
    ) %>%
    as_tibble()

# Splitting into training and test sets
split_index <- round(nrow(df) * 0.8)
training_set <- df[1:split_index, ] %>% as.data.frame()
testing_set <- df[(split_index + 1):nrow(df), ] %>% as.data.frame()

# Define a hidden Markov model with 2 states for the training set
hid1 <- MarkovChain$new(data = training_set, n_states = 2)
dists <- list(OILPRICE = "norm")
par0 <- list(OILPRICE = list(mean = c(110, 90), sd = c(1, 1)))
obs1 <- Observation$new(data = training_set, n_states = 2, dists = dists, par = par0)
par0 <- obs1$suggest_initial()
obs1 <- Observation$new(data = training_set, n_states = 2, dists = dists, par = par0)
hmm1 <- HMM$new(obs = obs1, hid = hid1)
hmm1$fit(silent = TRUE)

# Rename
data_plot <- training_set

# Color by most likely state sequence
data_plot$state <- factor(paste0("State ", hmm1$viterbi()))
ggplot(data_plot, aes(day, OILPRICE, col = state)) +
    geom_point() +
    scale_color_manual(values = pal, name = NULL)

# Attempting to make a one-step-ahead prediction
# ??? This is where I need guidance

enter image description here

如何使用hmmTMB对观察到的状态进行一步预测(例如,第二天的OILPRICE)在我的测试数据集(testing_set)上使用拟合模型(hmm 1)?我正在寻找一种方法来预测future 的OILPRICE值的基础上,模型拟合到训练集.

我很感激任何关于如何使用hmmTMB包来实现这一点的见解或例子.

推荐答案

目前,hmmTMB中没有内置的预测功能(截至2024年2月).然而,预测分布可以从拟合的hmm TMB模型计算出来.

预测分布是状态依赖分布的混合,其中权重对应于处于不同状态的概率.因此,您可以使用以下工作流:

  1. 获取最后观察到的数据行的状态分布(即,在时间n);让我们称其为u
  2. 得到时间n+h的状态分布为u %*% (tpm %^% h),其中tpm是状态过程的(一步)转移概率矩阵;也就是说,我们将u乘以h步转移概率矩阵
  3. 将预测分布作为估计的状态相关分布的混合,按上一步中找到的状态概率进行加权

例如,在步骤3中,您可以计算预测平均值(作为状态相关平均值的加权和),或预测分布的概率密度函数,如下面的代码所示.

预测均值与时间

黑点表示训练集最后一次观测后60天的预测分布的平均值.

预测均值与时间

预测分配

这些线条显示了训练集最后一次观测后60天的预测分布的概率密度函数.正如您所看到的,它很可能一开始处于状态2,因此相应的状态依赖分布具有更高的权重.一段时间后,随着状态分布接近平稳(长期)分布,预测分布停止变化.

预测分配s

代码

# Load packages
library(scico)
library(expm)

# Grid of oil prices to plot forecast distributions
grid <- seq(min(training_set$OILPRICE), 
            max(training_set$OILPRICE), 
            length = 100)

# Get state distribution at last (training) observation
sp <- hmm1$state_probs()
u <- sp[nrow(sp),]

# Get model parameters
tpm <- hid1$tpm()[,,1]
obspar <- obs1$par()[,,1]

# Loop over forecast times (over 60 days here)
h <- 1:60
mix <- list()
mix_mean <- rep(NA, length = length(h))
for(i in seq_along(h)) {
    # State distribution at time n + h
    dist_h <- u %*% (tpm %^% h[i])
    
    # 预测分配 at time n + h
    mix[[i]] <- 
        dist_h[1] * dnorm(x = grid, 
                          mean = obspar["OILPRICE.mean", "state 1"], 
                          sd = obspar["OILPRICE.sd", "state 1"]) +
        dist_h[2] * dnorm(x = grid, 
                          mean = obspar["OILPRICE.mean", "state 2"], 
                          sd = obspar["OILPRICE.sd", "state 2"])
    
    # Mean of forecast distribution
    mix_mean[i] <- sum(dist_h * obspar["OILPRICE.mean",])
}

# Plot the forecast mean against time
df_mean <- data.frame(day = seq.Date(from = as.Date("2020-10-20"), 
                                     by = "day", length = length(h)),
                      mean = mix_mean)

ggplot(data_plot, aes(day, OILPRICE, col = state)) +
    geom_point() +
    geom_point(aes(y = mean, col = NULL), data = df_mean) +
    scale_color_manual(values = pal)

# Plot the forecast distributions for h = 1, 2, ..., 60
df_mix <- data.frame(h = rep(h, each = 100),
                 price = grid,
                 mix = unlist(mix))

ggplot(df_mix, aes(price, mix, col = h, group = h)) +
    geom_line() +
    scale_color_scico(name = "time") +
    labs(y = "forecast distribution")

编辑

请注意,我使用了一个略有不同的模拟数据集,该数据集是从2状态隐马尔可夫模型生成的,以创建我们期望在真实数据中找到的那种模式.数据可以模拟如下:

# Set seed for reproducibility
set.seed(123)

# Generate state process for simulated data
markov <- rep(1, 366)
for(i in 2:366) {
    switch <- sample(0:1, size = 1, prob = c(0.95, 0.05))
    if(switch) markov[i] <- 3 - markov[i-1]
    else markov[i] <- markov[i-1]
}

# Example dataset preparation (extended for 1 year)
df <- data.frame(
    day = seq.Date(from = as.Date("2020-01-01"), 
                   to = as.Date("2020-12-31"), 
                   by = "day"),
    
    # Generate observations conditionally on state process
    OILPRICE = rnorm(366, c(100, 140)[markov], 10)
)

R相关问答推荐

将模拟变量乘以多个观测结果中的模拟变量

无法将传奇添加到cowplot多情节中

在R中创建一个包含转换和转换之间的时间的列

使用gcuminc,如何使用逗号格式化风险表?

在另一个函数中调用ggplot2美学

如何在所有绘图中保持条件值的 colored颜色 相同?

使用列/行匹配将两个不同维度的矩阵相加

矩阵的堆叠条形图,条形图上有数字作为标签

如何用书面利率绘制geom_bar图

哪一行和行和 Select 特定行,但是考虑到Nas

R中有约束的优化问题:如何用复数和对数效益函数解决问题?

如何使这些react 表对象相互独立?

R+reprex:在呈现R标记文件时创建可重现的示例

手动指定从相同数据创建的叠加图的 colored颜色

使用列中的值来调用函数调用中应使用的其他列

在不重复主题的情况下重新排列组

策略表单连接两个非常大的箭头数据集,而不会 destruct 内存使用

使用一个标签共享多个组图图例符号

使用dplyr删除具有条件的行

用逗号拆分字符串,并删除一些字符