RでOne-hot Encodingをする with tidyverse
あけまして
おめでとうございます。今年もよろしくお願いします。
新年の抱負は以下に書きました。
One-hot Encodingをやるパッケージが使えない
過去にこんな記事を書きました。
最近気づいたことにここで使っているパッケージdummies
がCRANから削除されているっぽいです。
install.packages("dummies") Warning in install.packages : package ‘dummies’ is not available for this version of R A version of this package for your version of R might be available elsewhere, see the ideas at https://cran.r-project.org/doc/manuals/r-patched/R-admin.html#Installing-packages
しょうがないなあ、と思ったのでこれをtidyverse
でどうにかします。
2023/01/07追記
これを書いた数分後(!?)にAtusyさんがこんな記事を。
tidymodels
での実装です。はやい。
どちらが優れているか、とかはよくわからないですが、モデルに組み込むことが前提であれば、
tidymodels
での実装がスマートかもしれないですね。
tidyverse
のスタイルに慣れている場合は僕のやり口がいいかもしれない。どっちでも。
考え方
One-hot Encodingはカテゴリ変数をダミー変数に変換する操作なので、
- すべて1を返す
value
列を定義 tidyr::pivot_wider()
でワイド変換
という操作を行います。
pivot_wider()
にはいくつか引数があり、names_from
にダミー変数にしたいカテゴリ変数、
values_from
には上記1で作ったvalue
を指定します。
pivot_wider()
自体はこれで動きますが、デフォルトの場合はそのカテゴリが該当しない場合の値はNA
です。
# A tibble: 32 × 32 car_name…¹ car_n…² car_n…³ car_n…⁴ car_n…⁵ car_n…⁶ car_n…⁷ car_n…⁸ car_n…⁹ car_n…˟ car_n…˟ car_n…˟ <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 1 NA NA NA NA NA NA NA NA NA NA NA 2 NA 1 NA NA NA NA NA NA NA NA NA NA 3 NA NA 1 NA NA NA NA NA NA NA NA NA 4 NA NA NA 1 NA NA NA NA NA NA NA NA 5 NA NA NA NA 1 NA NA NA NA NA NA NA 6 NA NA NA NA NA 1 NA NA NA NA NA NA 7 NA NA NA NA NA NA 1 NA NA NA NA NA 8 NA NA NA NA NA NA NA 1 NA NA NA NA 9 NA NA NA NA NA NA NA NA 1 NA NA NA 10 NA NA NA NA NA NA NA NA NA 1 NA NA # … with 22 more rows, 20 more variables: `car_name_Merc 450SL` <dbl>, `car_name_Merc 450SLC` <dbl>, # `car_name_Cadillac Fleetwood` <dbl>, `car_name_Lincoln Continental` <dbl>, # `car_name_Chrysler Imperial` <dbl>, `car_name_Fiat 128` <dbl>, `car_name_Honda Civic` <dbl>, # `car_name_Toyota Corolla` <dbl>, `car_name_Toyota Corona` <dbl>, # `car_name_Dodge Challenger` <dbl>, `car_name_AMC Javelin` <dbl>, `car_name_Camaro Z28` <dbl>, # `car_name_Pontiac Firebird` <dbl>, `car_name_Fiat X1-9` <dbl>, `car_name_Porsche 914-2` <dbl>, # `car_name_Lotus Europa` <dbl>, `car_name_Ford Pantera L` <dbl>, `car_name_Ferrari Dino` <dbl>, … # ℹ Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names
そのためvalues_fill
に0を指定して実行するとよくできるでしょう。
ちなみにデータがネストしている場合はdplyr::group_by() %>% dplyr::summarise()
などで集約してから。
今回は特にデータがネストしていない場合を用います。
library(tidyverse) data("mtcars") mtcars %>% dplyr::mutate( car_names = row.names(.), dummy_value = 1) %>% tidyr::pivot_wider( names_from = "car_names", names_prefix = "car_name_", values_from = "dummy_value", values_fill = 0 ) %>% dplyr::select(contains("car_name_")) # A tibble: 32 × 32 car_nam…¹ car_n…² car_n…³ car_n…⁴ car_n…⁵ car_n…⁶ car_n…⁷ car_n…⁸ car_n…⁹ car_n…˟ car_n…˟ car_n…˟ <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 1 0 0 0 0 0 0 0 0 0 0 0 2 0 1 0 0 0 0 0 0 0 0 0 0 3 0 0 1 0 0 0 0 0 0 0 0 0 4 0 0 0 1 0 0 0 0 0 0 0 0 5 0 0 0 0 1 0 0 0 0 0 0 0 6 0 0 0 0 0 1 0 0 0 0 0 0 7 0 0 0 0 0 0 1 0 0 0 0 0 8 0 0 0 0 0 0 0 1 0 0 0 0 9 0 0 0 0 0 0 0 0 1 0 0 0 10 0 0 0 0 0 0 0 0 0 1 0 0 # … with 22 more rows, 20 more variables: `car_name_Merc 450SL` <dbl>, # `car_name_Merc 450SLC` <dbl>, `car_name_Cadillac Fleetwood` <dbl>, # `car_name_Lincoln Continental` <dbl>, `car_name_Chrysler Imperial` <dbl>, # `car_name_Fiat 128` <dbl>, `car_name_Honda Civic` <dbl>, `car_name_Toyota Corolla` <dbl>, # `car_name_Toyota Corona` <dbl>, `car_name_Dodge Challenger` <dbl>, # `car_name_AMC Javelin` <dbl>, `car_name_Camaro Z28` <dbl>, `car_name_Pontiac Firebird` <dbl>, # `car_name_Fiat X1-9` <dbl>, `car_name_Porsche 914-2` <dbl>, `car_name_Lotus Europa` <dbl>, … # ℹ Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names
特定のカテゴリのダミー変数が知りたいならdplyr::select()
で指定すればよいですね。
なお、pythonでもpandas.get_dummies()
で可能です。
どっちもどっちですが、ダミー変数のための変数を作らなくて良い分、回りくどさがないのはpythonかもしれない。