prophet模型

使用R实现prophet模型,拟合和预测疾病发生率数据


日期

基本介绍

prophet模型

Prophet 是由 Facebook 开发的一种用于时间序列预测的开源算法。与传统的 ARIMA 模型不同,Prophet 采用了一种更加灵活和易于使用的建模方法。下面我来详细解释一下 Prophet 模型的主要特点有加法模型、灵活的趋势建模、季节性建模、节假日效应、易用性、鲁棒性等等。

prophet模型的示例:

1.加载所需要的包

library(prophet)
library(ggplot2)
library(dplyr)
library(zoo)
library(Metrics)
library(moments)

2.数据处理

# 读取数据
df <- read.csv('data.csv')
df$ds <- as.Date(df$ds, format = "%Y/%m/%d")

# 检查并处理缺失值
missing_count <- sum(is.na(df$y))
if(missing_count > 0) {
  cat(sprintf("发现%d个缺失值,使用线性插值填充\n", missing_count))
  df$y <- na.approx(df$y, na.rm = FALSE)
}

# 检测和处理异常值
mean_val <- mean(df$y, na.rm = TRUE)
sd_val <- sd(df$y, na.rm = TRUE)
outliers <- df$y[abs(df$y - mean_val) > 3*sd_val]
if(length(outliers) > 0) {
  cat(sprintf("发现%d个异常值\n", length(outliers)))
  df$y[df$y > mean_val + 3*sd_val] <- mean_val + 3*sd_val
  df$y[df$y < mean_val - 3*sd_val] <- mean_val - 3*sd_val
}
发现39个异常值
# 检查是否需要对数变换
skewness <- moments::skewness(df$y)
log_transform <- FALSE
if(skewness > 1) {
  cat("数据存在偏态,进行对数变换\n")
  df$y <- log1p(df$y)
  log_transform <- TRUE
}
# 设置节假日
chinese_holidays <- data.frame(
  holiday = 'chinese_new_year',
  ds = as.Date(c('2016-02-07','2016-02-08','2016-02-09',
                 '2017-01-28','2017-01-29','2017-01-30',
                 '2018-02-16','2018-02-17','2018-02-18',
                 '2019-02-05','2019-02-06','2019-02-07',
                 '2020-01-25','2020-01-26','2020-01-27',
                 '2021-02-12','2021-02-13','2021-02-14',
                 '2022-02-01','2022-02-02','2022-02-03',
                 '2023-01-22','2023-01-23','2023-01-24',
                 '2024-02-01','2024-02-11','2024-02-12')),  
  lower_window = -1,
  upper_window = 3
)

3.配置并训练模型

model <- prophet(
  df,
  holidays = chinese_holidays,
  yearly.seasonality = TRUE,
  weekly.seasonality = TRUE,
  daily.seasonality = FALSE,
  changepoint.prior.scale = 0.05,  # 控制趋势灵活性
  seasonality.prior.scale = 10.0,   # 控制季节性强度
  holidays.prior.scale = 10.0      # 控制节假日效应强度
)

4.预测

future <- make_future_dataframe(model, periods = 365)
forecast <- predict(model, future)

# 如果进行了对数变换,需要转换回原始尺度
if(log_transform) {
  forecast$yhat <- expm1(forecast$yhat)
  forecast$yhat_lower <- expm1(forecast$yhat_lower)
  forecast$yhat_upper <- expm1(forecast$yhat_upper)
  df$y <- expm1(df$y)
}

4.模型评估

# 计算误差指标
actual <- df$y
predicted <- forecast$yhat[1:length(actual)]

mae <- mean(abs(actual - predicted))
rmse <- sqrt(mean((actual - predicted)^2))
mape <- mean(abs((actual - predicted) / actual)) * 100

cat(sprintf("\n模型评估指标:
MAE:  %.2f
RMSE: %.2f
MAPE: %.2f%%\n",
            mae, rmse, mape))
模型评估指标:
MAE:  0.37
RMSE: 0.52
MAPE: 4.44%

模型评估结果:

MAE为0.37说明预测值平均偏离实际值不到半个单位,表现相当不错。RMSE略大于MAE说明存在一些较大的预测误差,但差距不大 MAPE (平均绝对百分比误差) = 4.44;MAPE小于5%通常被认为是很好的预测精度。三个指标都显示模型具有很好的预测精度。

5.交叉验证

cv_results <- cross_validation(model, initial = 730,
                               period = 365, horizon = 365,
                               units = 'days')
cv_metrics <- performance_metrics(cv_results)
cv_summary <- data.frame(
  Metric = c("MAE", "RMSE", "MAPE"),
  Mean = c(
    mean(cv_metrics$mae),
    mean(cv_metrics$rmse),
    mean(cv_metrics$mape)
  ),
  SD = c(
    sd(cv_metrics$mae),
    sd(cv_metrics$rmse),
    sd(cv_metrics$mape)
  )
)
# 打印格式化结果
print(format(cv_summary, digits = 2))
  Metric  Mean    SD
 1    MAE 0.553 0.164
 2   RMSE 0.678 0.180
 3   MAPE 0.068 0.019

交叉验证结果:

所有指标的标准差相对较小,说明模型在不同时期的预测性能比较稳定。MAE 和 RMSE 的差距合理,说明没有特别极端的预测偏差。

6.1可视化结果-预测结果图

# 预测结果图
p <- plot(model, forecast) +
  ggtitle("Prophet 时间序列预测") +
  xlab("日期") +
  ylab("值") +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 10)
  )

# 高亮节假日
if (!is.null(model$holidays)) {
  holidays_df <- model$holidays
  p <- p + geom_vline(data = holidays_df, 
                      aes(xintercept = as.numeric(ds)), 
                      color = "red", 
                      linetype = "dashed", 
                      alpha = 0.5)
}

# 显示预测区间
p <- p + geom_ribbon(aes(ymin = yhat_lower, ymax = yhat_upper), 
                     alpha = 0.2, 
                     fill = "blue")
print(p)

预测结果图呈现明显的周期性:数据呈现规律的上下波动,可能是年度或季节性模式。

6.2可视化结果-季节性分解图

# 绘制季节性分解图
p2 <- prophet_plot_components(model, forecast)

季节性分解图结果:

趋势项:2016-2020年间有轻微波动,2020年达到峰值后开始下降,预测未来趋势继续下滑。 节假日效应:春节期间有明显的负向效应,效应强度相对稳定。 周度效应(weekly):周二、周三最低,周四到周六逐渐上升。 年度效应(yearly):显示明显的季节性模式,7-12月为高峰期,4-6月为低谷期。

6.3可视化结果-残差图

# 绘制残差分析图
residuals <- actual - predicted
p3 <- ggplot() +
  geom_point(aes(x = df$ds, y = residuals)) +
  geom_hline(yintercept = 0, color = "red", linetype = "dashed") +
  labs(title = "残差时间序列图",
       x = "日期",
       y = "残差") +
  theme_minimal()
print(p3)

# 残差分布图
p4 <- ggplot() +
  geom_histogram(aes(x = residuals, y = ..density..), bins = 30) +
  geom_density(aes(x = residuals)) +
  labs(title = "残差分布图",
       x = "残差",
       y = "密度") +
  theme_minimal()
print(p4)

残差图结果:

残差分布图分析:呈现钟形曲线,接近正态分布,这表明模型预测误差分布合理,没有明显的系统性偏差。 残差时间序列图分析:残差在0线附近随机分布,没有明显的趋势或模式,残差的波动强度相对稳定。

7.评估指标

metrics <- data.frame(
  metric = c("MAE", "RMSE", "MAPE"),
  value = c(mae, rmse, mape)
)
# 创建包含所有评估指标的数据框
metrics_combined <- data.frame(
  Metric = c("MAE", "RMSE", "MAPE"),
  Training = c(mae, rmse, mape),
  CV_Mean = c(mean(cv_metrics$mae), mean(cv_metrics$rmse), mean(cv_metrics$mape)),
  CV_SD = c(sd(cv_metrics$mae), sd(cv_metrics$rmse), sd(cv_metrics$mape))
)

# 打印评估指标结果
print(format(metrics_combined, digits = 2))
  Metric Training CV_Mean CV_SD
1    MAE     0.37   0.553 0.164
2   RMSE     0.52   0.678 0.180
3   MAPE     4.44   0.068 0.019

评估指标结果:

模型拟合质量好,预测误差分布合理;并且成功捕捉了数据的主要季节性模式,交叉验证结果显示模型具有良好的泛化能力,但是MAPE指标的训练集和交叉验证集差异较大,可以考虑实际应用中在节假日效应中加入其他重要节日。

潘洁
格兰芬多优等麻瓜