きぬいとさんがtidyverseでOne-hot Encodingしているのを見ましたが、餅は餅屋でtidymodelsもいいよねという話。
tidymodelsは統計・機械学習モデリングを統一的なフレームワークに落とし込む存在です。こう書くと、前処理から推論、評価まで全部を行う時を想定しがちですが、つまみ食いして前処理だけ任せるのもアリでしょう。
というわけで、こんな感じの、a、b、cの水準からなるx列を含むデータフレームを対象にOne-hot encodingしてみます。
data <- data.frame(id = seq(4L), x = c("a", "b", "c", "c"))
data
#> id x
#> 1 1 a
#> 2 2 b
#> 3 3 c
#> 4 4 c
Tidymodelsでは前処理をする前に、その「レシピ」を作ります。今回みたいにダミー変数を作りたいだけなら冗長に感じるかもしれませんが、これが中々重要な概念。
recipes::prep
関数でレシピを特定のデータで評価しパラメータを保存しておくので、未知のデータに使い回せます。
# レシピの用意と学習
rec <- recipes::recipe(
~ ., # モデル式。今回は目的変数を考えないので、~の左は空白
data = data # レシピの作成に使うデータ
) |>
recipes::step_dummy("x", one_hot = TRUE) |> # x列からダミー変数を作る
recipes::prep() # レシピの評価
レシピの適用はrecipes::bake
関数。レシピを用意した時と同じデータであれば、new_data = NULL
でOKです。これで、One-hot encoding完了。
# レシピの適用
recipes::bake(rec, new_data = NULL)
#> # A tibble: 4 × 4
#> id x_a x_b x_c
#> <int> <int> <int> <int>
#> 1 1 1 0 0
#> 2 2 0 1 0
#> 3 3 0 0 1
#> 4 4 0 0 1
ちなみに、recipes::step_dummy
関数で引数にone_hot = TRUE
を指定しましたが、FALSE
にすると、上記の結果からx_a
列が欠如します。
x_a
の情報はx_b
、x_c
から分かるので、モデリングには不要なものとして、既定値ではFALSE
が指定されています。
最後にレシピの有用性を確認しましょう。最初のデータは、a、b、cの3水準から成りました。
new_data
をつぃて、水準にdを含むデータフレームを与えるとどうなるでしょうか。
# 新規データへのレシピ適用
recipes::bake(rec, new_data = data.frame(id = c(5L, 6L), x = c("a", "d")))
#> Warning: There are new levels in a factor: d
#> # A tibble: 2 × 4
#> id x_a x_b x_c
#> <int> <int> <int> <int>
#> 1 5 1 0 0
#> 2 6 NA NA NA
recipes::prep
関数を適用した時に観測しなかった水準がある旨を警告してくれています。加えてx列の値が"d"
だった行では、x_a、x_b、x_cの各列の値がNA
になっています。
recipesパッケージを含むtidymodelsに入門したい人は、丁度今日に発売開始した、以下の本を読んでみると良いと思います。 tidymodelsは統計・機会学習モデリングを統一的なフレームワークに落としこんでくれる存在です。 Pythonにおけるscikit-learn的なものですが、「統一的」な代わりに巨大なので、日本語で全容を掴める書籍は貴重な存在です。
Rユーザのためのtidymodels[実践]入門 〜モダンな統計・機械学習モデリングの世界 https://gihyo.jp/book/2023/978-4-297-13236-1
ENJOY!