One Hot encodingをR/Pythonで実装

スポンサーリンク
Python
スポンサーリンク

機械学習の勉強を進めて行く中でOne Hot encodingという単語に出くわしました。

One Hot encodingとは、カテゴリー変数を機械学習のアルゴリズムが学習しやすいように0と1で表現する処理のことです。

縦持ちのカテゴリー変数を、横持ちにすることで、機械学習のモデル生成がうまくいくので、ちょくちょくしなければならない前処理です。

 

デジタル回路において、one-hot(ワン・ホット)は1つだけHigh(1)であり、他はLow(0)であるようなビット列のことを指す 類似のものとして、0が1つだけで、他がすべて1であるようなビット列をone-cold(ワン・コールド)と呼ぶことがある

One-hot - Wikipedia

 

スポンサーリンク

売上データを使った例

会社によくあるケースとして、売れた商品と売上金額が入っているDBを考えてみましょう。

 

One Hot encoding前

このように格納してあるDBは多いのではないでしょうか。普通に利用する分には良いのですが、機械学習では少し使いづらい形です。

id item sales
1 A 1000
2 B 2000
3 C 3000

 

One Hot encoding後

One Hot encodingの処理を加えると、品名の列を、品名A、品目B、品名Cに分けて、ブーリアン型の0か1がセットされます。0と1をセットするので二値化(binarization)とも言います。

id sales itemA itemB itemC
1 1000 1 0 0
2 2000 0 1 0
3 3000 0 0 1

 

このカテゴリー変数を分割する処理をOne Hot encodingと呼びます。

 

実装

いつもお世話になっている前処理大全(P154.第7章 展開)に横持ちから縦持ちにする方法で、One Hot encodingが実現できます。

created by Rinker
¥2,112 (2024/04/21 11:27:15時点 Amazon調べ-詳細)

 

Pythonで計算

import pandas as pd
import numpy as np

ファイルの読み込み¶

df = pd.read_table('~/Desktop/analysis/blog/input/onehot.csv')

df.head(5)
id item sales
0 1 A 1000
1 2 B 2000
2 3 C 3000

モデルの作成¶

# index='sale' : グルーピングしたい列(表示したい列)をセット
# columns='item' : one hot encodingしたいカテゴリ変数をセット
# values='id' : カテゴリ変数の値(0か1)として利用する、aggfuncで利用する引数なのでid、sales、item、どれでも良い
# aggfunc=lambda x: len(x), fill_value=0 : valuesの個数をカウント(0か1)、値がなかったときに0をセット
pd_onehot = pd.pivot_table(df, 
                           index=['id', 'sales'], 
                           columns='item' ,
                           values='id' ,
                           aggfunc=lambda x: len(x), fill_value=0)

pd_onehot
item A B C
id sales
1 1000 1 0 0
2 2000 0 1 0
3 3000 0 0 1

ファイルの出力¶

# forecastのデータをcsvで出力
pd_onehot.to_csv('~/Desktop/analysis/blog/output/onehot.py.csv')

 

Rで計算

library('tidyverse')
library('dplyr')

ファイルの読み込み¶

df = read.table(file = '~/Desktop/analysis/blog/input/onehot.csv', header = TRUE)

df
id item sales
1 A 1000
2 B 2000
3 C 3000

One Hot encoding¶

# カテゴリ型に変換
df$item <- as.factor(df$item )
# group_by(id, item, sales) : グルーピングしたい列(表示したい列)をセット
# summarise(cnt=n()) : グルーピングした列でのカウント、idがユニークであるので必ず1になる
# spread(item, cnt, fill=0) : 表示したい列からone hot encodingしたいカテゴリ変数をセット、cntの値(=1)、値がなかったときに0をセット
df.onehot <- df %>%
    group_by(id, item, sales) %>%
    summarise(cnt=n()) %>%
    spread(item, cnt, fill=0)

df.onehot
id sales A B C
1 1000 1 0 0
2 2000 0 1 0
3 3000 0 0 1

ファイルに出力¶

# ファイルに書き出す
write.csv(df.onehot, file = '~/Desktop/analysis/blog/output/df.onehot.csv', row.names = T)

 

カテゴリー変数を数字として扱って機械学習するのは何故ダメなのか?

モデルが正しく生成できないからです。カテゴリー変数の品名A、B、Cに優劣、平均はありません。

 

例えば品名A、B、C、を1、2、3に変換してモデル生成をすると、1(A)よりも3(C)の方が良い製品、という間違ったモデルを生成してしまいます。

 

また、数字として扱うと品目の平均をとれることになるので、1(A)+2(B)+3(C)=6/3=2(B)となります。これは品名の平均は2(B)になる、という誤ったモデルが生成されてしまうことになります。

 

品名に優劣、平均という概念はありませんが、数字ラベルを用いるとこのようなおかしなモデルを作ってしまうのでカテゴリー変数を数字で扱うのがダメなのです。

 

参考リンク

What is One Hot Encoding? Why And When do you have to use it? | HackerNoon
So, you’re playing with ML models and you encounter this “One hot encoding” term all over the place. You see the sklearn documentation for one hot encoder and i...

コメント

タイトルとURLをコピーしました