【R】Time Series Machine Learning
1. はじめに
時系列データの機械学習をしてみます。timetk
というパッケージを使います。データは、UCI Machine Learning Repositoryからレンタルバイクのデータを利用します。こちらのtimetike
のVignetteを参考にしました。
2. データ
2.1 準備
必要なパッケージを読み込みます。
library(tidymodels) library(modeltime) library(tidyverse) library(timetk) interactive = TRUE #Plotをインタラクティブに
2.2 データ
データは、UCI Machine Learning RepositoryからBike Sharing Datasetを使用します。
Source: Fanaee-T, Hadi, and Gama, Joao, ‘Event labeling combining ensemble detectors and background knowledge’, Progress in Artificial Intelligence (2013): pp. 1-15, Springer Berlin Heidelberg
レンタルバイク事業で得られたデータです。今回は、日付dteday
と貸出数cnt
を用います。
bike_transactions_tbl <- bike_sharing_daily %>% select(dteday, cnt) %>% set_names(c("date", "value")) bike_transactions_tbl
> bike_transactions_tbl
# A tibble: 731 x 2
date value
<date> <dbl>
1 2011-01-01 985
2 2011-01-02 801
3 2011-01-03 1349
4 2011-01-04 1562
5 2011-01-05 1600
6 2011-01-06 1606
7 2011-01-07 1510
8 2011-01-08 959
9 2011-01-09 822
10 2011-01-10 1321
# ... with 721 more rows
2.3 データの確認
データをプロットして確認します。plot_time_series
関数で時系列データとしてプロットします。interactive=FALSEにすると、インタラクティブではなく、ggplotのプロットとなります。トレンドと周期性とノイズが程よく入っているデータっぽいですね。
bike_transactions_tbl %>% plot_time_series(date, value, .interactive = interactive)
3. 機械学習
3.1 データ準備
学習用とテスト用のデータを準備します。3か月分をテスト用とします(assess=”3 months”)。
splits <- bike_transactions_tbl %>% time_series_split(assess = "3 months", cumulative = TRUE)
学習用/テスト用データをプロットして確認します。
splits %>% tk_time_series_cv_plan() %>% #dataframeに変換 plot_time_series_cv_plan(date, value, .interactive = interactive) #データをプロット
3.2 モデリング
目的変数をvalue
としてrecipe
を作ります。timetk
パッケージでは機械学習をサポートしてくれるstep_timeseries_signature()
という関数があります。
recipe_spec_timeseries <- recipe(value ~ ., data = training(splits)) %>% step_timeseries_signature(date)
bake
して機械学習に必要なデータセットを生成します。
bake(prep(recipe_spec_timeseries), new_data = training(splits))
> bake(prep(recipe_spec_timeseries), new_data = training(splits))
# A tibble: 641 x 29
date value date_index.num date_year date_year.iso date_half date_quarter date_month date_month.xts
<date> <dbl> <int> <int> <int> <int> <int> <int> <int>
1 2011-01-01 985 1293840000 2011 2010 1 1 1 0
2 2011-01-02 801 1293926400 2011 2010 1 1 1 0
3 2011-01-03 1349 1294012800 2011 2011 1 1 1 0
4 2011-01-04 1562 1294099200 2011 2011 1 1 1 0
5 2011-01-05 1600 1294185600 2011 2011 1 1 1 0
6 2011-01-06 1606 1294272000 2011 2011 1 1 1 0
7 2011-01-07 1510 1294358400 2011 2011 1 1 1 0
8 2011-01-08 959 1294444800 2011 2011 1 1 1 0
9 2011-01-09 822 1294531200 2011 2011 1 1 1 0
10 2011-01-10 1321 1294617600 2011 2011 1 1 1 0
# ... with 631 more rows, and 20 more variables: date_month.lbl <ord>, date_day <int>, date_hour <int>,
# date_minute <int>, date_second <int>, date_hour12 <int>, date_am.pm <int>, date_wday <int>, date_wday.xts <int>,
# date_wday.lbl <ord>, date_mday <int>, date_qday <int>, date_yday <int>, date_mweek <int>, date_week <int>,
# date_week.iso <int>, date_week2 <int>, date_week3 <int>, date_week4 <int>, date_mday7 <int>
recipe_spec_final <- recipe_spec_timeseries %>% step_fourier(date, period = 365, K = 5) %>% step_rm(date) %>% step_rm(contains("iso"), contains("minute"), contains("hour"), contains("am.pm"), contains("xts")) %>% step_normalize(contains("index.num"), date_year) %>% step_dummy(contains("lbl"), one_hot = TRUE) juice(prep(recipe_spec_final))
> juice(prep(recipe_spec_final))
# A tibble: 641 x 47
value date_index.num date_year date_half date_quarter date_month date_day date_second date_wday date_mday date_qday
<dbl> <dbl> <dbl> <int> <int> <int> <int> <int> <int> <int> <int>
1 985 -1.73 -0.869 1 1 1 1 0 7 1 1
2 801 -1.72 -0.869 1 1 1 2 0 1 2 2
3 1349 -1.72 -0.869 1 1 1 3 0 2 3 3
4 1562 -1.71 -0.869 1 1 1 4 0 3 4 4
5 1600 -1.71 -0.869 1 1 1 5 0 4 5 5
6 1606 -1.70 -0.869 1 1 1 6 0 5 6 6
7 1510 -1.70 -0.869 1 1 1 7 0 6 7 7
8 959 -1.69 -0.869 1 1 1 8 0 7 8 8
9 822 -1.68 -0.869 1 1 1 9 0 1 9 9
10 1321 -1.68 -0.869 1 1 1 10 0 2 10 10
# ... with 631 more rows, and 36 more variables: date_yday <int>, date_mweek <int>, date_week <int>,
# date_week2 <int>, date_week3 <int>, date_week4 <int>, date_mday7 <int>, date_sin365_K1 <dbl>,
# date_cos365_K1 <dbl>, date_sin365_K2 <dbl>, date_cos365_K2 <dbl>, date_sin365_K3 <dbl>, date_cos365_K3 <dbl>,
# date_sin365_K4 <dbl>, date_cos365_K4 <dbl>, date_sin365_K5 <dbl>, date_cos365_K5 <dbl>, date_month.lbl_01 <dbl>,
# date_month.lbl_02 <dbl>, date_month.lbl_03 <dbl>, date_month.lbl_04 <dbl>, date_month.lbl_05 <dbl>,
# date_month.lbl_06 <dbl>, date_month.lbl_07 <dbl>, date_month.lbl_08 <dbl>, date_month.lbl_09 <dbl>,
# date_month.lbl_10 <dbl>, date_month.lbl_11 <dbl>, date_month.lbl_12 <dbl>, date_wday.lbl_1 <dbl>,
# date_wday.lbl_2 <dbl>, date_wday.lbl_3 <dbl>, date_wday.lbl_4 <dbl>, date_wday.lbl_5 <dbl>,
# date_wday.lbl_6 <dbl>, date_wday.lbl_7 <dbl>
モデルを指定します。今回は、線形回帰とします。
model_spec_lm <- linear_reg(mode = "regression") %>% set_engine("lm")
レシピとモデルを決めたので、ワークフローを設定します。
workflow_lm <- workflow() %>% add_recipe(recipe_spec_final) %>% add_model(model_spec_lm) workflow_lm
> workflow_lm
== Workflow ====================================================================
Preprocessor: Recipe
Model: linear_reg()
-- Preprocessor ----------------------------------------------------------------
6 Recipe Steps
* step_timeseries_signature()
* step_fourier()
* step_rm()
* step_rm()
* step_normalize()
* step_dummy()
-- Model -----------------------------------------------------------------------
Linear Regression Model Specification (regression)
Computational engine: lm
学習します。
workflow_fit_lm <- workflow_lm %>% fit(data = training(splits))
3.3 予測
modeltime
パッケージを使って、予測します。
model_table <- modeltime_table( workflow_fit_lm ) model_table
> model_table
# Modeltime Table
# A tibble: 1 x 3
.model_id .model .model_desc
<int> <list> <chr>
1 1 <workflow> LM
キャリブレーション
calibration_table <- model_table %>% modeltime_calibrate(testing(splits)) calibration_table
> calibration_table
# Modeltime Table
# A tibble: 1 x 5
.model_id .model .model_desc .type .calibration_data
<int> <list> <chr> <chr> <list>
1 1 <workflow> LM Test <tibble [90 x 4]>
テスト用データで予測してみます。
calibration_table %>% modeltime_forecast(actual_data = bike_transactions_tbl) %>% plot_modeltime_forecast(.interactive = interactive)
予測精度(テスト用データ)を見てみます。
calibration_table %>% modeltime_accuracy() %>% table_modeltime_accuracy(.interactive = interactive)
最後に、4年後(=48months)までの予測をしてみます。
calibration_table %>% modeltime_refit(bike_transactions_tbl) %>% modeltime_forecast(h = "48 months", actual_data = bike_transactions_tbl) %>% plot_modeltime_forecast(.interactive = interactive)
なんだか、それらしい予測データとなっています。
4. さいごに
timetk
パッケージとmodeltime
パッケージを使って、時系列データの機械学習をしてみました。今後、活用していきたいです。