对时间序列数据使用随机森林

机器算法验证 时间序列 随机森林
2022-02-08 11:55:54

这是一个简单的问题,可以在时间序列数据上使用随机森林模型吗?我问这个是因为,在随机森林模型中,我们执行自举观察,我们从训练集中随机抽样并替换。这不会破坏模型中的“观察顺序”,因为它是时间序列数据。我是在金融数据的背景下问这个问题的,比如说我正在做一个分类类型的问题来购买/不购买资产,并且我收集了一些功能的日常数据来预测这个变量。

2个回答

它工作得很好,但前提是功能准备得当,这样行的顺序就不再重要了。

例如对于单变量时间序列yi,你会使用yi作为响应,例如以下功能:

  1. 滞后版本yi1,yi2,yi3等等

  2. 适当顺序的差异,例如 yi1yi2,yi1yi8(如果预计每周有季节性并且每天都会进行观察)等。

  3. 整数或虚拟编码的周期性时间信息,例如一年中的月份、星期几、一天中的小时、小时中的分钟等。

相同的方法适用于不同的建模技术,包括线性回归、神经网络、增强树等。

下面是一个示例(使用二进制目标“温度升高”(y/n)):

library(tidyverse)
library(lubridate)
library(ranger)
library(MetricsWeighted) # AUC

# Import
raw <- read.csv("https://raw.githubusercontent.com/jbrownlee/Datasets/master/daily-min-temperatures.csv")

# Explore
str(raw)
head(raw)
summary(raw)
hist(raw$Temp, breaks = "FD")

# Prepare and add binary response
prep <- raw %>% 
  mutate(Date = ymd(Date),
         y = year(Date),
         m = month(Date),
         d = day(Date),
         increase = 0 + (Temp > lag(Temp)))

with(prep, table(y))
summary(prep)

# Plot full data -> year as seasonality
ggplot(data = prep, aes(x = Date, y = Temp))+
  geom_line(color = "#00AFBB", size = 2) +
  scale_x_date()

# No visible within year seasonality
prep %>% 
  filter(y == 1987) %>% 
ggplot(aes(x = Date, y = Temp))+
  geom_line(color = "#00AFBB", size = 2) +
  scale_x_date()

# Add some lags and diffs & remove incomplete rows
prep <- prep %>% 
  mutate(lag1 = lag(Temp),
         lag2 = lag(Temp, 2L),
         lag3 = lag(Temp, 3L),
         dif1 = lag1 - lag2,
         dif2 = lag2 - lag3) %>% 
  filter(complete.cases(.))

# Train/valid split in blocks
valid <- prep %>% 
  filter(y == 1990)
train <- prep %>% 
  filter(y < 1990)

# Models
y <- "increase" # response
x <- c("lag1", "lag2", "lag3", "dif1", "dif2", "y", "m", "d") # covariables
form <- reformulate(x, y)

# Logistic model: Linear dependence between difs and lags
fit_glm <- glm(form, 
               data = train, 
               family = binomial()) 
summary(fit_glm)

# Random forest
fit_rf <- ranger(form, 
                 data = train,
                 seed = 345345, 
                 importance = "impurity", 
                 probability = TRUE)
fit_rf
barplot(-sort(-importance(fit_rf))) # Variable importance

# Evaluate on 1990 for glm by looking at ROC AUC
pred_glm <- predict(fit_glm, valid, type = "response")
AUC(valid[[y]], pred_glm) # 0.684 ROC AUC

# Then for rf
pred_rf <- predict(fit_rf, valid)$predictions[, 2]
AUC(valid[[y]], pred_rf)    # 0.702 ROC AUC

# view OOB residuals of rf within one month to see if structure is left over
random_month <- train %>% 
  mutate(residuals = increase - fit_rf$predictions[, 2]) %>% 
  filter(y == 1987, m == 3) 

ggplot(random_month, aes(x = Date, y = residuals))+
  geom_line(color = "#00AFBB", size = 2) +
  scale_x_date()

用因子替换变量“y”和“m”可能会改善逻辑回归。但由于问题是关于随机森林的,我把这个留给读者。

由于各种原因,随机森林不会在时间序列数据上表现良好。然而,在我看来,最大的陷阱与引导无关,也不是随机森林所独有的:

  1. 时间序列在观察之间具有相互依赖性,模型将忽略这一点。
  2. 底层学习器通常是基于树的算法,它不会推断趋势。如果数据中有真正的时间趋势,则不会向前预测。