经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » R语言 » 查看文章
时间序列分析工具箱—— h2o + timetk
来源:cnblogs  作者:xuruilong100  时间:2018/9/25 20:19:34  对本文有异议

目录

翻译自《Demo Week: Time Series Machine Learning with h2o and timetk》

原文链接:https://www.business-science.io/code-tools/2017/10/28/demo_week_h2o.html

文字和代码略有删改

时间序列分析工具箱—— h2o + timetk

h2o 的用途

h2o 包是 H2O.ai 提供的产品,包含许多先进的机器学习算法,表现指标和辅助函数,使机器学习功能强大而且容易使用。h2o 的主要优点之一是它可以部署在集群上(今天不会讨论),从 R 的角度来看,有四个主要用途:

  1. 数据操作:拼接、分组、旋转、传输、拆分成训练 / 测试 / 验证集,等等。
  2. 机器学习算法:包含非常复杂的监督和非监督学习算法。监督学习算法包括深度学习(神经网络)、随机森林、广义线性模型、梯度增强机、朴素贝叶斯分析、模型堆叠集成和 xgboost;无监督算法包括广义低秩模型、k 均值模型和 PCA;还有 Word2vec 用于文本分析。最新的稳定版本还有 AutoML——自动机器学习,我们将在这篇文章中看到这个非常酷的功能!
  3. 辅助机器学习功能:表现分析和超参数网格搜索。
  4. 产品、MapReduce 和 云:Java 环境下进行产品化;使用 Hadoop / Spark(Sparkling Water)进行集群部署;在云环境(Azure、AWS、Databricks 等)中部署。

我们将讨论如何将 h2o 用作时间序列机器学习的一种高级算法。我们将在本地使用 h2o,在先前关于 timetksweep 的教程中使用的数据集(beer_sales_tbl)上开发一个高精度的时间序列模型。这是一个监督学习的回归问题。

加载包

我们需要三个包:

  • h2o:机器学习算法包
  • tidyquant:用于获取数据和加载 tidyverse 系列工具
  • timetk:R 中的时间序列工具箱

安装 h2o

推荐在 ubuntu 环境下安装最新稳定版 h2o

加载包

  1. # Load libraries
  2. library(h2o) # Awesome ML Library
  3. library(timetk) # Toolkit for working with time series in R
  4. library(tidyquant) # Loads tidyverse, financial pkgs, used to get data

数据

我们使用 tidyquant 的函数 tq_get(),获取 FRED 的数据——啤酒、红酒和蒸馏酒销售

  1. # Beer, Wine, Distilled Alcoholic Beverages, in Millions USD
  2. beer_sales_tbl <- tq_get(
  3. "S4248SM144NCEN",
  4. get = "economic.data",
  5. from = "2010-01-01",
  6. to = "2017-10-27")
  7. beer_sales_tbl
  1. ## # A tibble: 92 x 2
  2. ## date price
  3. ## <date> <int>
  4. ## 1 2010-01-01 6558
  5. ## 2 2010-02-01 7481
  6. ## 3 2010-03-01 9475
  7. ## 4 2010-04-01 9424
  8. ## 5 2010-05-01 9351
  9. ## 6 2010-06-01 10552
  10. ## 7 2010-07-01 9077
  11. ## 8 2010-08-01 9273
  12. ## 9 2010-09-01 9420
  13. ## 10 2010-10-01 9413
  14. ## # ... with 82 more rows

可视化是一个好主意,我们要知道我们正在使用的是什么数据,这对于时间序列分析和预测尤为重要,并且最好将数据分成训练、测试和验证集。

  1. # Plot Beer Sales with train, validation, and test sets shown
  2. beer_sales_tbl %>%
  3. ggplot(aes(date, price)) +
  4. # Train Region
  5. annotate(
  6. "text",
  7. x = ymd("2012-01-01"), y = 7000,
  8. color = palette_light()[[1]],
  9. label = "Train Region") +
  10. # Validation Region
  11. geom_rect(
  12. xmin = as.numeric(ymd("2016-01-01")),
  13. xmax = as.numeric(ymd("2016-12-31")),
  14. ymin = 0, ymax = Inf, alpha = 0.02,
  15. fill = palette_light()[[3]]) +
  16. annotate(
  17. "text",
  18. x = ymd("2016-07-01"), y = 7000,
  19. color = palette_light()[[1]],
  20. label = "Validation\nRegion") +
  21. # Test Region
  22. geom_rect(
  23. xmin = as.numeric(ymd("2017-01-01")),
  24. xmax = as.numeric(ymd("2017-08-31")),
  25. ymin = 0, ymax = Inf, alpha = 0.02,
  26. fill = palette_light()[[4]]) +
  27. annotate(
  28. "text",
  29. x = ymd("2017-05-01"), y = 7000,
  30. color = palette_light()[[1]],
  31. label = "Test\nRegion") +
  32. # Data
  33. geom_line(col = palette_light()[1]) +
  34. geom_point(col = palette_light()[1]) +
  35. geom_ma(ma_fun = SMA, n = 12, size = 1) +
  36. # Aesthetics
  37. theme_tq() +
  38. scale_x_date(
  39. date_breaks = "1 year",
  40. date_labels = "%Y") +
  41. labs(title = "Beer Sales: 2007 through 2017",
  42. subtitle = "Train, Validation, and Test Sets Shown")

现在我们对数据有了直观的认识,让我们继续吧。

教程:h2o + timetk,时间序列机器学习

我们的时间序列机器学习项目遵循的工作流与之前 timetk + 线性回归文章中的类似。但是,这次我们将用 h2o.autoML() 替换 lm() 函数以获得更高的准确性。

时间序列机器学习

时间序列机器学习是预测时间序列数据的好方法,在开始之前,先明确教程的两个关键问题:

  • 关键洞察时间序列签名——将时间戳信息逐列扩展,成为特征集,用于执行机器学习算法。
  • 目标:我们将用时间序列签名预测未来 8 个月的数据,并和先前教程中出现的两种方法(即 timetk + lm()sweep + auto.arima())的预测结果作对比。

下面,我们将经历一遍执行时间序列机器学习的工作流。

STEP 0:检查数据

作为分析的起点,先用 glimpse() 打印出 beer_sales_tbl,获得数据的第一印象。

  1. # Starting point
  2. beer_sales_tbl %>%
  3. glimpse()
  1. ## Observations: 92
  2. ## Variables: 2
  3. ## $ date <date> 2010-01-01, 2010-02-01, 2010-03-01, 2010-04-01, 20...
  4. ## $ price <int> 6558, 7481, 9475, 9424, 9351, 10552, 9077, 9273, 94...

STEP 1:扩充时间序列签名

tk_augment_timeseries_signature() 函数将时间戳信息逐列扩展成机器学习所用的特征集,将时间序列信息列添加到原始数据框。再次使用 glimpse() 进行快速检查。现在有了 30 个特征,有些特征很重要,但并非所有特征都重要。

  1. # Augment (adds data frame columns)
  2. beer_sales_tbl_aug <- beer_sales_tbl %>%
  3. tk_augment_timeseries_signature()
  4. beer_sales_tbl_aug %>% glimpse()
  1. ## Observations: 92
  2. ## Variables: 30
  3. ## $ date <date> 2010-01-01, 2010-02-01, 2010-03-01, 2010-04-01...
  4. ## $ price <int> 6558, 7481, 9475, 9424, 9351, 10552, 9077, 9273...
  5. ## $ index.num <int> 1262304000, 1264982400, 1267401600, 1270080000,...
  6. ## $ diff <int> NA, 2678400, 2419200, 2678400, 2592000, 2678400...
  7. ## $ year <int> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,...
  8. ## $ year.iso <int> 2009, 2010, 2010, 2010, 2010, 2010, 2010, 2010,...
  9. ## $ half <int> 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,...
  10. ## $ quarter <int> 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 1, 1, 1, 2,...
  11. ## $ month <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3,...
  12. ## $ month.xts <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, ...
  13. ## $ month.lbl <ord> January, February, March, April, May, June, Jul...
  14. ## $ day <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  15. ## $ hour <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  16. ## $ minute <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  17. ## $ second <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  18. ## $ hour12 <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  19. ## $ am.pm <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  20. ## $ wday <int> 6, 2, 2, 5, 7, 3, 5, 1, 4, 6, 2, 4, 7, 3, 3, 6,...
  21. ## $ wday.xts <int> 5, 1, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3, 6, 2, 2, 5,...
  22. ## $ wday.lbl <ord> Friday, Monday, Monday, Thursday, Saturday, Tue...
  23. ## $ mday <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  24. ## $ qday <int> 1, 32, 60, 1, 31, 62, 1, 32, 63, 1, 32, 62, 1, ...
  25. ## $ yday <int> 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 30...
  26. ## $ mweek <int> 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5,...
  27. ## $ week <int> 1, 5, 9, 13, 18, 22, 26, 31, 35, 40, 44, 48, 1,...
  28. ## $ week.iso <int> 53, 5, 9, 13, 17, 22, 26, 30, 35, 39, 44, 48, 5...
  29. ## $ week2 <int> 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1,...
  30. ## $ week3 <int> 1, 2, 0, 1, 0, 1, 2, 1, 2, 1, 2, 0, 1, 2, 0, 1,...
  31. ## $ week4 <int> 1, 1, 1, 1, 2, 2, 2, 3, 3, 0, 0, 0, 1, 1, 1, 1,...
  32. ## $ mday7 <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...

STEP 2:为 h2o 准备数据

我们需要以 h2o 的格式准备数据。首先,让我们删除任何不必要的列,如日期列或存在缺失值的列,并将有序类型的数据更改为普通因子。我们推荐用 dplyr 操作这些步骤。

  1. beer_sales_tbl_clean <- beer_sales_tbl_aug %>%
  2. select_if(~ !is.Date(.)) %>%
  3. select_if(~ !any(is.na(.))) %>%
  4. mutate_if(is.ordered, ~ as.character(.) %>% as.factor)
  5. beer_sales_tbl_clean %>% glimpse()
  1. ## Observations: 92
  2. ## Variables: 28
  3. ## $ price <int> 6558, 7481, 9475, 9424, 9351, 10552, 9077, 9273...
  4. ## $ index.num <int> 1262304000, 1264982400, 1267401600, 1270080000,...
  5. ## $ year <int> 2010, 2010, 2010, 2010, 2010, 2010, 2010, 2010,...
  6. ## $ year.iso <int> 2009, 2010, 2010, 2010, 2010, 2010, 2010, 2010,...
  7. ## $ half <int> 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1,...
  8. ## $ quarter <int> 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 1, 1, 1, 2,...
  9. ## $ month <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3,...
  10. ## $ month.xts <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, ...
  11. ## $ month.lbl <fctr> January, February, March, April, May, June, Ju...
  12. ## $ day <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  13. ## $ hour <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  14. ## $ minute <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  15. ## $ second <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  16. ## $ hour12 <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,...
  17. ## $ am.pm <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  18. ## $ wday <int> 6, 2, 2, 5, 7, 3, 5, 1, 4, 6, 2, 4, 7, 3, 3, 6,...
  19. ## $ wday.xts <int> 5, 1, 1, 4, 6, 2, 4, 0, 3, 5, 1, 3, 6, 2, 2, 5,...
  20. ## $ wday.lbl <fctr> Friday, Monday, Monday, Thursday, Saturday, Tu...
  21. ## $ mday <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
  22. ## $ qday <int> 1, 32, 60, 1, 31, 62, 1, 32, 63, 1, 32, 62, 1, ...
  23. ## $ yday <int> 1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 30...
  24. ## $ mweek <int> 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5,...
  25. ## $ week <int> 1, 5, 9, 13, 18, 22, 26, 31, 35, 40, 44, 48, 1,...
  26. ## $ week.iso <int> 53, 5, 9, 13, 17, 22, 26, 30, 35, 39, 44, 48, 5...
  27. ## $ week2 <int> 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1,...
  28. ## $ week3 <int> 1, 2, 0, 1, 0, 1, 2, 1, 2, 1, 2, 0, 1, 2, 0, 1,...
  29. ## $ week4 <int> 1, 1, 1, 1, 2, 2, 2, 3, 3, 0, 0, 0, 1, 1, 1, 1,...
  30. ## $ mday7 <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...

让我们在可视化之前按照时间范围将数据分成训练、验证和测试集。

  1. # Split into training, validation and test sets
  2. train_tbl <- beer_sales_tbl_clean %>% filter(year < 2016)
  3. valid_tbl <- beer_sales_tbl_clean %>% filter(year == 2016)
  4. test_tbl <- beer_sales_tbl_clean %>% filter(year == 2017)

STEP 3:h2o 模型

首先,启动 h2o。这将初始化 h2o 使用的 java 虚拟机。

  1. h2o.init() # Fire up h2o
  1. ## Connection successful!
  2. ##
  3. ## R is connected to the H2O cluster:
  4. ## H2O cluster uptime: 46 minutes 4 seconds
  5. ## H2O cluster version: 3.14.0.3
  6. ## H2O cluster version age: 1 month and 5 days
  7. ## H2O cluster name: H2O_started_from_R_mdancho_pcs046
  8. ## H2O cluster total nodes: 1
  9. ## H2O cluster total memory: 3.51 GB
  10. ## H2O cluster total cores: 4
  11. ## H2O cluster allowed cores: 4
  12. ## H2O cluster healthy: TRUE
  13. ## H2O Connection ip: localhost
  14. ## H2O Connection port: 54321
  15. ## H2O Connection proxy: NA
  16. ## H2O Internal Security: FALSE
  17. ## H2O API Extensions: Algos, AutoML, Core V3, Core V4
  18. ## R Version: R version 3.4.1 (2017-06-30)
  1. h2o.no_progress() # Turn off progress bars

将数据转成 H2OFrame 对象,使得 h2o 包可以读取。

  1. # Convert to H2OFrame objects
  2. train_h2o <- as.h2o(train_tbl)
  3. valid_h2o <- as.h2o(valid_tbl)
  4. test_h2o <- as.h2o(test_tbl)

为目标和预测变量命名。

  1. # Set names for h2o
  2. y <- "price"
  3. x <- setdiff(names(train_h2o), y)

我们将使用 h2o.automl,在数据上尝试任何回归模型。

  • x = x:特征列的名字
  • y = y:目标列的名字
  • training_frame = train_h2o:训练集,包括 2010 - 2016 年的数据
  • validation_frame = valid_h2o:验证集,包括 2016 年的数据,用于避免模型的过度拟合
  • leaderboard_frame = test_h2o:模型基于测试集上 MAE 的表现排序
  • max_runtime_secs = 60:设置这个参数用于加速 h2o 模型计算。算法背后有大量复杂模型需要计算,所以我们以牺牲精度为代价,保证模型可以正常运转。
  • stopping_metric = "deviance":把偏离度作为停止指标,这可以改善结果的 MAPE。
  1. # linear regression model used, but can use any model
  2. automl_models_h2o <- h2o.automl(
  3. x = x,
  4. y = y,
  5. training_frame = train_h2o,
  6. validation_frame = valid_h2o,
  7. leaderboard_frame = test_h2o,
  8. max_runtime_secs = 60,
  9. stopping_metric = "deviance")

接着,提取主模型。

  1. # Extract leader model
  2. automl_leader <- automl_models_h2o@leader

STEP 4:预测

使用 h2o.predict() 在测试数据上产生预测。

  1. pred_h2o <- h2o.predict(
  2. automl_leader, newdata = test_h2o)

STEP 5:评估表现

有几种方法可以评估模型表现,这里,将通过简单的方法,即 h2o.performance()。这产生了预设值,这些预设值通常用于比较回归模型,包括均方根误差(RMSE)和平均绝对误差(MAE)。

  1. h2o.performance(
  2. automl_leader, newdata = test_h2o)
  1. ## H2ORegressionMetrics: gbm
  2. ##
  3. ## MSE: 340918.3
  4. ## RMSE: 583.8821
  5. ## MAE: 467.8388
  6. ## RMSLE: 0.04844583
  7. ## Mean Residual Deviance : 340918.3

我们偏好的评估指标是平均绝对百分比误差(MAPE),未包括在上面。但是,我们可以轻易计算出来。我们可以查看测试集上的误差(实际值 vs 预测值)。

  1. # Investigate test error
  2. error_tbl <- beer_sales_tbl %>%
  3. filter(lubridate::year(date) == 2017) %>%
  4. add_column(
  5. pred = pred_h2o %>% as.tibble() %>% pull(predict)) %>%
  6. rename(actual = price) %>%
  7. mutate(
  8. error = actual - pred,
  9. error_pct = error / actual)
  10. error_tbl
  1. ## # A tibble: 8 x 5
  2. ## date actual pred error error_pct
  3. ## <date> <int> <dbl> <dbl> <dbl>
  4. ## 1 2017-01-01 8664 8241.261 422.7386 0.048792541
  5. ## 2 2017-02-01 10017 9495.047 521.9534 0.052106763
  6. ## 3 2017-03-01 11960 11631.327 328.6726 0.027480989
  7. ## 4 2017-04-01 11019 10716.038 302.9619 0.027494498
  8. ## 5 2017-05-01 12971 13081.857 -110.8568 -0.008546509
  9. ## 6 2017-06-01 14113 12796.170 1316.8296 0.093306142
  10. ## 7 2017-07-01 10928 10727.804 200.1962 0.018319563
  11. ## 8 2017-08-01 12788 12249.498 538.5016 0.042109915

为了比较,我们计算了一些残差度量指标。

  1. error_tbl %>%
  2. summarise(
  3. me = mean(error),
  4. rmse = mean(error^2)^0.5,
  5. mae = mean(abs(error)),
  6. mape = mean(abs(error_pct)),
  7. mpe = mean(error_pct)) %>%
  8. glimpse()
  1. ## Observations: 1
  2. ## Variables: 5
  3. ## $ me <dbl> 440.1246
  4. ## $ rmse <dbl> 583.8821
  5. ## $ mae <dbl> 467.8388
  6. ## $ mape <dbl> 0.03976961
  7. ## $ mpe <dbl> 0.03763299

STEP 6:可视化预测结果

最后,可视化我们得到的预测结果。

  1. beer_sales_tbl %>%
  2. ggplot(aes(x = date, y = price)) +
  3. # Data - Spooky Orange
  4. geom_point(col = palette_light()[1]) +
  5. geom_line(col = palette_light()[1]) +
  6. geom_ma(
  7. n = 12) +
  8. # Predictions - Spooky Purple
  9. geom_point(
  10. aes(y = pred),
  11. col = palette_light()[2],
  12. data = error_tbl) +
  13. geom_line(
  14. aes(y = pred),
  15. col = palette_light()[2],
  16. data = error_tbl) +
  17. # Aesthetics
  18. theme_tq() +
  19. labs(
  20. title = "Beer Sales Forecast: h2o + timetk",
  21. subtitle = "H2O had highest accuracy, MAPE = 3.9%")

最终的胜利者是...

h2o + timetk 的 MAPE 优于先前两个教程中的方法:

感兴趣的读者要问一个问题:对所有三种不同方法的预测进行平均时,准确度会发生什么变化?

请注意,时间序列机器学习的准确性可能并不总是优于 ARIMA 和其他预测技术,包括那些由 prophet(Facebook 开发的预测工具)和 GARCH 方法实现的技术。数据科学家有责任测试不同的方法并为工作选择合适的工具。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号