tidymodels
tidymodels
は統一的なインターフェースでモデリングを行うための、いくつかのパッケージをまとめたもの。
rsample
:訓練データ/テストデータの分割recipe
:データの前処理(変数変換、サンプリングなど)parsnip
:モデリングyardstic
:モデルの精度評価
データの分割 : rsample パッケージ
Train/Test 分割 : initial_split()
set.seed(10)
dm_split <- rsample::initial_split(data, prop = 3/4, strata = NULL, breaks = 4, ...)
# 時系列データの分割の場合
# dm_split <- initial_time_split(data, prop = 3/4, lag = 0, ...)
# 訓練データとテストデータのと取り出し
train_df <- rsample::training(dm_split)
test_df <- rsample::testing(dm_split)
prop
: 訓練データの割合strata
: 層化サンプリングに使用する変数を指定する。(ここで指定した変数の値の頻度分布は、訓練データとテストデータで同じになる)breaks
: 整数スカラー。層化サンプリングしたい変数が連続変数の時に、連続地をいくつのビンに分けるか指定する。lag
: テストと訓練の間にラグを含めるための値。これはラグのある予測変数が使用される場合に便利です。
交差検証のための分割 : vfold_cv()
K交差検証
rsample::vfold_cv(data, v = 10, repeats = 1, strata = NULL, breaks = 4, ...)
data
: データフレームv
: CVの分割数 (fold数)repeats
: CVの分割を何回繰り返すか。総計算回数はv*repeats
になる。strata
: 層化サンプリング。CV分割の時に、fold間で割合を維持したい変数を指定する(例えば目的変数がカテゴリ変数の時に指定する)breaks
: 整数スカラー。層化サンプリングしたい変数が連続変数の時に、連続地をいくつのビンに分けるか指定する。
グループK交差検証
rsample::group_vfold_cv(data, group = NULL, v = NULL, ...)
data
: データフレームgroup
: グルーピングに使いたい変数名1つv
: データを分割したい数、NULL
の場合はグルーピング変数のユニークな値の数になる
Foldのデータを参照する
各Foldのデータを取り出すには以下の関数を使用する
analysis()
: 訓練データを参照するassessment()
: 検証データを参照する
vfold_cv()
関数の出力値は vfold_cv
オブジェクト、これは実際にはネストされたデータフレームである。
df_cv <- rsample::vfold_cv(data, v = 10, repeats = 1)
> class(df_cv)
[1] "vfold_cv" "rset" "tbl_df" "tbl" "data.frame"
ある1つの訓練・検証データのペアを取り出す
train <- rsample::analysis(df_cv$splits[[1]])
validation <- rsample::assessment(df_cv$splits[[1]])
リピートなしの分割
> df_cv <- rsample::vfold_cv(dm_info_train_df, strata = "month", v = 2, repeats = 1)
> df_cv
# 2-fold cross-validation using stratification
# A tibble: 2 x 2
splits id
<list> <chr>
1 <rsplit [363/364]> Fold1
2 <rsplit [364/363]> Fold2
リピートありの分割
> df_cv <- rsample::vfold_cv(dm_info_train_df, strata = "month", v = 2, repeats = 2)
> df_cv
# 2-fold cross-validation repeated 2 times using stratification
# A tibble: 4 x 3
splits id id2
<list> <chr> <chr>
1 <rsplit [363/364]> Repeat1 Fold1
2 <rsplit [364/363]> Repeat1 Fold2
3 <rsplit [363/364]> Repeat2 Fold1
4 <rsplit [364/363]> Repeat2 Fold2
前処理 : recipes パッケージ
訓練や新規データへのモデルの適用の前に実施する変数変換やデータサンプリングの手順をレシピオブジェクトとして定義する。
recipes
パッケージで実施する前処理とは、特徴量作成というよりも、対数変換や標準化などデータの本質的な意味は変えないが、アルゴリズムの学習を適切に行えるようにするための処理のことを指す。
そのため、この前処理は特徴量作成の後モデリングの直前に実施する。
レシピオブジェクトの作成 : recipe()
最初に、変数加工のためのパラメタ(標準化のための平均と分散など)を決めるために使う訓練データ(一般には訓練データ)
そのデータに含まれる目的変数と説明変数をフォーミュラとして与える。
モデル式(目的変数と説明変数)を指定
recipes::recipe(x, formula = NULL, ..., vars = NULL, roles = NULL)
x
,data
: 変数加工のためのパラメタ(標準化のための平均と分散など)を決めるために使う訓練データformula
: モデル式、目的変数と説明変数の指定。log(x)
とかx:y
などの関数を含めてはいけない。マイナス符号をつけるのもダメ。vars
: 変数名を格納した文字列ベクトルroles
:vars
と同じ長さの文字列ベクトル。各変数の役割を指定する。"outcome", "predictor", "case_weight", or "ID"
他の値でもいい
mod_rec <-
df_rental %>%
recipes::recipe(formula = Y ~ Area)
各前処理ステップの定義 : step_*()
データに対する加工は step_*()
関数を使う
dplyr
step_filter
Filter rows using dplyrstep_arrange
Sort rows using dplyrstep_mutate
Add new variables using ‘mutate’step_mutate_at
Mutate multiple columnsstep_rename
Rename variables by namestep_rename_at
Rename multiple columnsstep_slice
Filter rows by position using dplyr
数値データ変換
step_center
Centering numeric datastep_cut
Cut a numeric variable into a factorstep_discretize
Discretize Numeric Variablesstep_normalize
Center and scale numeric datastep_log
Logarithmic Transformationstep_logit
Logit Transformationstep_BoxCox
Box-Cox Transformation for Non-Negative Datastep_hyperbolic
Hyperbolic Transformationsstep_inverse
Inverse Transformationstep_invlogit
Inverse Logit Transformationstep_range
Scaling Numeric Data to a Specific Rangestep_relu
Apply (Smoothed) Rectified Linear Transformationstep_scale
Scaling Numeric Datastep_sqrt
Square Root Transformationstep_YeoJohnson
Yeo-Johnson Transformation
カテゴリ変数 factor
step_factor2string
Convert Factors to Stringsstep_integer
Convert values to predefined integersstep_bin2factor
Create a Factors from A Dummy Variablestep_novel
Simple Value Assignments for Novel Factor Levelsstep_num2factor
Convert Numbers to Factorsstep_other
Collapse Some Categorical Levelsstep_ordinalscore
Convert Ordinal Factors to Numeric Scoresstep_relevel
Relevel factors to a desired levelstep_string2factor
Convert Strings to Factorsstep_unknown
Assign missing categories to “unknown”step_unorder
Convert Ordered Factors to Unordered Factors
変数取捨選択
-
step_shuffle
Shuffle Variables -
step_rm
General Variable Filter -
step_zv
Zero Variance Filter -
step_nzv
Near-Zero Variance Filter -
step_corr
High Correlation Filter -
step_lincomb
Linear Combination Filter
#変数追加
step_count
Create Counts of Patterns using Regular Expressionsstep_ratio
Ratio Variable Creation
時系列
step_date
Date Feature Generatorstep_holiday
Holiday Feature Generatorstep_lag
Create a lagged predictor
サンプリング
step_downsample
Down-Sample a Data Set Based on a Factor Variablestep_sample
Sample rows using dplyrstep_upsample
Up-Sample a Data Set Based on a Factor Variable
統計モデリング
step_dummy
Dummy Variables Creationstep_interact
Create Interaction Variablesstep_intercept
Add intercept (or constant) columnstep_regex
Create Dummy Variables using Regular Expressions
地理情報
step_geodist
Distance between two locationsstep_spatialsign
Spatial Sign Preprocessing
欠損値
step_naomit
Remove observations with missing values
欠損値補完 : imputation
step_knnimpute
Imputation via K-Nearest Neighborsstep_lowerimpute
Impute Numeric Data Below the Threshold of Measurementstep_meanimpute
Impute Numeric Data Using the Meanstep_medianimpute
Impute Numeric Data Using the Medianstep_modeimpute
Impute Nominal Data Using the Most Common Valuestep_impute_linear
Imputation of numeric variables via a linear model.step_bagimpute
Imputation via Bagged Treesstep_rollimpute
Impute Numeric Data Using a Rolling Window Statistic
抽出? : Extraction
step_ica
ICA Signal Extractionstep_kpca
Kernel PCA Signal Extractionstep_kpca_poly
Polynomial Kernel PCA Signal Extractionstep_kpca_rbf
Radial Basis Function Kernel PCA Signal Extractionstep_nnmf
NNMF Signal Extractionstep_pca
PCA Signal Extractionstep_pls
Partial Least Squares Feature Extraction
その他
-
step_bs
B-Spline Basis Functions -
step_ns
Natural Spline Basis Functions -
step_poly
Orthogonal Polynomial Basis Functions -
step_window
Moving Window Functions -
step_classdist
Distances to Class Centroids -
step_depth
Data Depths -
step_isomap
Isomap Embedding -
step_profile
Create a Profiling Version of a Data Set
サンプリング・ステップ
# サンプリングを含むレシピを作成 (prep()しない)
sampling_recipe <-
recipes::recipe(Y ~ ., data = train_df) %>%
# 目的変数 Y の値に基づいてサンプリングする
# 訓練データに対してはサンプリングするが
# テストデータや新規データに対してはサンプリングしない場合は skip = TRUE を指定する。
# この時点でサンプリングのための乱数 seed は固定される
themis::step_downsample(Y, under_ratio = 0.5, skip = TRUE) %>%
# prep() を実行すると skip = TRUE を指定したステップも実行される
# retain = TRUE で、最初に渡した train_df にレシピが適用されたデータを
# レシピオブジェクトの中に保持する
recipes::prep(retain = TRUE)
# サンプリングが適用されたデータの作成方法
# 1. レシピオブジェクトの中に存在する
# レシピ適用済みデータを取り出す
sampled_train_df <-
sampling_recipe$template
# 2. レシピオブジェクトの中に存在する
# レシピ適用済みデータを bake(newdata=NULL) で取り出す
sampled_train_df <-
sampling_recipe %>%
bake(newdata=NULL)
# 注意:bake() に新データを渡して新データにレシピを適用したときには、サンプリングステップ は実行されない。(正確は `skip = TRUE` が指定されたステップは実行されない)
NOT_sampled_test_df <-
sampling_recipe %>%
bake(newdata=test_df) # newdata で渡したデータにはサンプリングは適用されない
サンプリングを含んだクロスバリデーション
クロスバリデーションをするときには、Validation データにはサンプリングを実施しないが、学習データに対してはサンプリングを実施したい。
# CVのために(サンプリングをされていない)訓練データを分割する
df_cv <-
rsample::vfold_cv(train_df, v = 5, repeats = 1)
# サンプリングを含むレシピを作成 ()
# 注意するのはここでは prep() しないということ
sampling_recipe <-
recipes::recipe(Y ~ ., data = train_df) %>%
# テストデータや新規データに対してはサンプリングしない場合は skip = TRUE を指定する。
themis::step_downsample(Y, under_ratio = 0.5, skip = TRUE)
# このレシピを使ってクロスバリデーションをする場合には、ここでは prep() しない
# おそらく rsample::vfold_cv() の中で prep() される
# CV を実行する
cv_result_df <-
tune::tune_grid(
object = rnd_forest_model, # parsnip で作成したモデルオブジェクト
preprocessor = sampling_recipe,
resamples = df_cv,
grid = params_grid_df, # 探索したいパラメータの値が格納されたデータフレーム
metrics = yardstick::metric_set(yardstick::pr_auc, yardstick::roc_auc),
control = tune::control_grid(verbose = TRUE)
)
skip=TRUE
について
skip=TRUE
が指定されたステップは、 recipes::prep(retain = TRUE)
を実行したときには適用されるが、recipes::bake(newdata = new_df)
を実行したときには適用されない。
次のように考えてもよいかもしれない
recipes::prep()
は訓練データ作成用にレシピを実行する。recipes::bake()
は新データ・テストデータ・検証データ作成用にレシピを実行する
skip = TRUE
を指定された処理は訓練データを作成するときには使用されるが、新データやテストデータや検証データに対しては使用されない。不均衡データ対策のためなど、目的変数を使ったサンプリングを実施するステップに対しては skip = TRUE
を指定する。
step_*() の中での変数の指定の仕方
step_log(all_predictors(), all_outcomes())
dplyrの starts_with() contains() 等も使える
prep() パラメータを持つステップの訓練・更新
rec_trained <-
prep(mod_rec, retain = TRUE, verbose = TRUE)
retain
: 処理済みの訓練データをオブジェクト内に保持する (template
スロット)。後からステップを追加したいが、既存のステップの再トレーニングを避けたい場合に良いアイデア。skip = FALSE
オプションを使用しているステップがある場合は、retain = TRUE
を使用することをお勧めします。training
: データ処理のパラメタ(標準化のための平均と分散とか)の訓練のために使うデータフレームを別に指定する場合fresh
:TRUE
なら、新たに訓練データを与えてパラメータを更新する。同時に、training
に新たな訓練データを与えること。fresh=TRUE
は前にprep()
したstep_*()
の方も更新する。fresh=FALSE
なら まだprep()
されていないstep_*()
を更新する。
レシピを新しいデータに適用する bake()
以前は bake()
は新データにレシピを適用する。 juice()
はレシピ内に保持されたデータに対してレシピを適用するという意味だったが。今は juice()
の代わりに bake(newdata=NULL)
を使うことが推奨されている。
モデリング : parsnip パッケージ
まずは目的に合わせてアルゴリズムを指定して、モデルオブジェクトを作成する。
parsnip
は異なるパッケージのアルゴリズムを同じインターフェースで扱えるようにする。
モデルオブジェクトの作成
以下のアルゴリズムが使用できる
parsnip::linear_reg()
parsnip::decision_tree()
parsnip::rand_forest()
それぞれのアルゴリズムで具体的にどのパッケージを使うかは parsnip::set_engine()
で指定する。この関数はさらに使用するパッケージの機械学習モデルに追加で渡す引数を指定することもできる。
rf_model <-
parsnip::linear_reg() %>%
parsnip::set_engine("ranger", , num.threads = 10, seed = 42, importance = "permutation)
Thanks @ailich. Yea, that may be a confusion point. I would condider to add the explanation on the Chapter on the LogicalVector.
I really appreciate this kinds of advice to make the book sensible for person who are not familiar to C++.
線形回帰 : parsnip::linear_reg()
linear_regression_model <-
parsnip::linear_reg() %>%
parsnip::set_engine("lm")
決定木 : parsnip::decision_tree()
# 分類木
decision_tree_model <-
parsnip::decision_tree(
mode = "classification",
cost_complexity = cost_complexity,
tree_depth = tree_depth,
min_n = min_n)
決定木とランダムフォレストの実行の仕方 (rpart
, ranger
) は以下のサイトが参考になる
https://www.marketechlabo.com/r-decision-tree/
ランダムフォレスト : parsnip::rand_forest()
parsnip::rand_forest(mode = "unknown", mtry = NULL, trees = NULL, min_n = NULL)
## S3 method for class 'rand_forest'
update(
object,
parameters = NULL,
mtry = NULL,
trees = NULL,
min_n = NULL,
fresh = FALSE,
...
)
- mode : Possible values for this model are “unknown”, “regression”, or “classification”.
- mtry: The number of predictors that will be randomly sampled at each split when creating the tree models.
- trees: The number of trees contained in the ensemble.
- min_n: The minimum number of data points in a node that are required for the node to be split further.
エンジン
parsnip::set_engine("ranger", num.threads = 10, seed = 42, importance = "permutation")
set_engine()
- R: “ranger” (the default) or “randomForest”
- Spark: “spark”
変数重要度
ranger
で変数重要度を計算させる場合は parsnip::set_engine()
に以下のいずれかを指定する
importance = 'impurity'
importance = 'permutation'
モデル学習
モデル学習の実行 : fit()
lm_fit <- # 学習済みモデルオブジェクト
lm_mod %>%
fit(width ~ initial_volume * food_regime, # 目的変数と説明変数をフォーミュラで指定
data = data_mart_df
)
学習済みモデルオブジェクトの内容を確認する
tidy(lm_fit)
# 線形回帰の学習済みオブジェクトを tidy() で処理した出力を dotwhisker::dwplot() に入力して結果を見る
tidy(lm_fit) %>%
dotwhisker::dwplot(dot_args = list(size = 2, color = "black"),
whisker_args = list(color = "black"),
vline = geom_vline(xintercept = 0, colour = "grey50", linetype = 2))
予測 : predict
mean_pred <-
predict(
object = lm_fit,
new_data = new_points,
type = "conf_int"
)
-
object
: 学習済みモデルオブジェクトmodel_fit
クラス -
new_data
: 予測を適用するデータ -
type
: 予測で出力する値のタイプ"numeric", "class", "prob", "conf_int", "pred_int", "quantile", or "raw"
、指定しない場合はモデルのmode
に合わせて適切に選ばれる -
opts
:type = "raw "
のときに使用される引数の値を指定したリスト -
...
: その他の引数level
:type
が"conf_int"
または"pred_int"
の時、ここでlevel=0.95
のように区間の値を指定する。std_error
:type
が"conf_int"
and"pred_int"
のときに、誤差の値も出力するか指定する。TRUE
なら出力する。FALSE
なら出力しない。デフォルトはFALSE
add the standard error of fit or prediction (on the scale of the linear predictors) for types of “conf_int” and “pred_int”. Default value is FALSE.
quantile
: the quantile(s) for quantile regression (not implemented yet)time
: the time(s) for hazard probability estimates (not implemented yet)
ハイパーパラメータ・チューニング : tune()
https://note.com/tqwst408/n/n2483a75d82a0
finetune パッケージを使うと精度が低いと考えられるハイパラの値については繰り返しを削減して計算効率を上げることができる。
クロスバリデーションのデータの分割
# Partitioning data for CV
df_cv <- rsample::vfold_cv(sampled_train_df, v = 5)
機械学習アルゴリズムとチューニングしたいハイパーパラメータを指定する
parsnip
パッケージでモデルオブジェクトを作成する際に、交差検証で探索したいハイパーパラメータを選ぶ。そのために、探索したいパラメータの値として tune::tune()
を指定する。
# モデルオブジェクトの作成と
# チューニングするハイパーパラメータの指定
rnd_forest_model <-
parsnip::rand_forest(
mode = "classification",
trees = tune::tune(),
min_n = tune::tune(),
mtry = tune::tune()
) %>%
parsnip::set_engine("ranger", num.threads = 10, seed = 42)
CVの並列化
あるパラメタ値について、CVの各Foldの計算を並列化するために foreach
パッケージを使用している。そのためには foreach
のバックエンドの設定をする必要がある。
# コア数を調べる
n.cores <- parallel::detectCores()
# クラスタを作成
my.cluster <- parallel::makeCluster(
n.cores, # 並列数は基本的にFold数と同じにする。Fold数よりも多くても意味がない。
type = "PSOCK" # Mac/Linux の場合は "FORK" にするそちらのほうが効率が良い
)
# 作成したクラスタを確認
print(my.cluster)
# 作成したクラスタを foreach に登録する
doParallel::registerDoParallel(cl = my.cluster)
# 登録されたか確認する
foreach::getDoParRegistered()
# クラスタを停止するとき
parallel::stopCluster(my.cluster)
グリッドサーチ: tune::tune_grid()
探索したいパラメータの範囲を指定した後で、その範囲の中からランダム・規則的に100個の点を抽出する。
# 探索するパラメータの範囲を指定した後で、
# その範囲の中からランダムに100個の点を抽出する
params_grid_df <-
list(
min_n = dials::min_n(range = c(100, 1000)),
mtry = dials::mtry(range = c(3, 5)),
trees = dials::trees(range = c(100, 1000))
) %>%
tune::parameters() %>%
# ランダムグリッドの場合
dials::grid_random(size = 100)
# レギュラーグリッドの場合
#dials::grid_regular(size = 100)
# クロスバリデーションの実行
cv_result_df <-
tune::tune_grid(
object = rnd_forest_model,
preprocessor = y ~ .,
resamples = df_cv,
grid = params_grid_df,
metrics = yardstick::metric_set(yardstick::pr_auc, yardstick::roc_auc),
control = tune::control_grid(verbose = TRUE)
)
object
:parsnip
パッケージで作成したモデルオブジェクト、あるいは 内部でモデルを保持したworkflows::workflow()
で作成したワークフローオブジェクトpreprocessor
: モデルフォーミュラ、あるいは、recipes::recipe()
で作成したレシピオブジェクトresamples
:rset
オブジェクト、rsample::vfold_cv()
の出力結果param_info
: 探索したいハイパーパラメータの値の範囲、dials::parameters()
オブジェクト、あるいはNULL
grid
: 1.param_info=NULL
の時、探索したい具体的なパラメータの値が記録されたデータフレーム(カラム名はハイパーパラメータ名と一致する)、 2. 正の整数値、param_info
に値が渡されたとき (param_info
の範囲からgrid
で指定された数のハイパーパラメータ点が探索される)metrics
: 計算したい精度指標をyardstick::metric_set()
を使って指定する。NULL
なら自動で選ばれるcontrol
: チューニングをいじるために使われるオブジェクト。control = tune::control_grid(verbose = TRUE)
でCVの経過を出力する(Sys.setlocale(locale="English")
をセットしないと一部文字化けする)。
ベイジアン最適化 : tune::tune_bayes()
# 探索するパラメータの範囲を指定する
# その範囲の中からランダムに100個の点する
params_grid_df <-
list(
min_n = dials::min_n(range = c(100, 1000)),
mtry = dials::mtry(range = c(3, 5)),
trees = dials::trees(range = c(100, 1000))
) %>%
tune::parameters()
# クロスバリデーションの実行
cv_result_df <-
tune::tune_grid(
object = rnd_forest_model,
preprocessor = y ~ .,
resamples = df_cv,
grid = params_grid_df,
metrics = yardstick::metric_set(yardstick::pr_auc, yardstick::roc_auc),
control = tune::control_grid(verbose = TRUE)
)
tune_bayes(
object,
...,
preprocessor,
resamples,
iter = 10,
param_info = NULL,
metrics = NULL,
objective = exp_improve(),
initial = 5,
control = control_bayes()
)
object
:parsnip
で作成したモデルオブジェクトか workflows::workflow()....
: オプション、内部で使われるGPfit::GP_fit()
に渡される引数 (主にはcorr
引数)preprocessor
: モデルフォーミュラかrecipes::recipe()
で作成したレシピresamples
:rset()
オブジェクトrsample::vfold_cv()
の返値とかiter
: 探索の繰り返しの最大回数param_info
: 探索したいパラメタの範囲を指定するdials::parameters()
オブジェクト。NULL
の場合は他の引数に基づいてパラメターセットが生成される。metrics
: 精度評価指標yardstick::metric_set()
オブジェクト。複数の指標を与えた場合には最初の指標が最適化される。objective
: どのメトリックを最適化すべきかを示す文字列、または 獲得関数(acquisition function
)オブジェクト(これなら複数の精度指標を組み合わせた最適化ができる??)。initial
: 初期値(tune_grid()
の結果と同様の形式、というかユーザーが事前計算したtune_grid()
の結果をtune_bayes()
に渡す)。あるいは正の整数(この場合は内部で自動でtune_grid()
をしてから計算する)。最初に渡す結果の数はパラメタの数よりも多いほうが良い。control
:control_bayes()
で作成した control オブジェクト
tune::fit_resamples()
CVのなかの1つの計算は tune::fit_resamples()
が使われている??
## S3 method for class 'model_spec'
fit_resamples(
object,
preprocessor,
resamples,
...,
metrics = NULL,
control = control_resamples()
)
## S3 method for class 'workflow'
fit_resamples(
object,
resamples,
...,
metrics = NULL,
control = control_resamples()
)
クロスバリデーションの結果の確認
tune::collect_metrics(cv_result_df) %>%
filter(.metric == "pr_auc") %>%
arrange(desc(mean))
ベストのパラメターで再学習
best_param <-
cv_result_df %>%
select_best(metric = "pr_auc") %>%
select(-.config)
model_best <- update(rnd_forest_model, best_param)
fitted_model <- fit(model_best,
formula = flag_detected_by_viirs ~ .,
data = sampled_train_df)
精度検証 : yardstick
yardstick::roc_auc()
yardstick::pr_auc()
yardstick::roc_curve()
yardstick::pr_curve()
yardstick::gain_curve()
yardstick::lift_curve()