tidymodelsでOne-hot Encodingする

by

きぬいとさんがtidyverseでOne-hot Encodingしているのを見ましたが、餅は餅屋でtidymodelsもいいよねという話。

RでOne-hot Encodingをする with tidyverse

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_bx_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!