※このページではアフィリエイト広告を利用しています

【機械学習入門】カテゴリカルデータの文字列を数字に変換する方法

Python

機械学習を行う際、前処理をする必要があります。そんなときに文字データをそのまま学習させるとエラーになる場合があります。

そのような場合、「category_encoders」などを用いて数値に変換(エンコード)することで回避する必要が出てきます。

そこで、ここでは文字列を数値に変換する方法を紹介しています。

この記事の対象

  • 順序尺度、名義尺度について知りたい方
  • エンコードの種類、方法を知りたい方
  • OneHotEncoder(0-1変数)の使用方法を知りたい方
スポンサーリンク
スポンサーリンク

カテゴリ変数とは?

カテゴリ変数とは、「定量的」ではないデータを指します。

回りくどいですが、「定量的ではないデータ」とは「数値型」ではないデータと言い換えられます。

例えば「性別」とか「評価(○×,合格,不合格)」などになります。補足ですが、数値であっても、クラスの1組、2組などの数値自体に意味のないもの(順序尺度)もカテゴリ変数となります。

整理すると、

  • 順序尺度:サイズ、階層、評価など
  • 名義尺度:性別、血液型、郵便番号など

となります。

カテゴリ変数を数値データに変換する目的

機械学習を行う際、決定木などはカテゴリ変数をそのまま扱うことができまが、ロジスティック回帰やニューラルネットワークでは、カテゴリ変数をそのまま使用すると悲惨なことになります。そこで、数値に変換して正しく機械に解釈させる必要があります。

ちなみに、これらの過程を「エンコーディング」と言われています。

エンコーディングの主な種類

代表的な数値化手法(エンコーディング)は以下になります。

  • Label Encoding:カテゴリを0~カテゴリ種類n-1の値を割り当てる。決定木分析、ランダムフォレストに適している。
  • One Hot Encoding:ダミー変数化する。多重共線性の問題が出る。回帰分析に適している。
  • Count Encoding:各カテゴリデータの頻出回数を数値として割り当てる。
  • Target Encoding:カテゴリごとに目的変数の平均情報を数値として割り当てる。

ここでは、「Label Encoding」「One Hot Encoding」「Count Encoding」の変換方法について解説しています。

順序尺度の数値化方法

例えば、テストの評価としてA,B,Cがあるとします。

これは「A>B>C」と順序がある尺度と解釈できます。この場合は「A→1」「B→2」「C→3」と数値化できます。

以下のようなデータがあるとします。

import pandas as pd
df = pd.DataFrame([
        ['A', 100, 'Math'],
        ['B', 50, 'Science'],
        ['C', 20, 'History']])
df.columns = ['evaluation', 'number', 'label']

出力結果は以下の通りです。

  evaluation  number    label
0          A     100     Math
1          B      50  Science
2          C      20  History

それでは、これを数値化すると以下のようになります。

change_eva = {'A': 1, 'B': 2, 'C': 3}
df['evaluation'] = df['evaluation'].map(change_eva)

【結果】

   evaluation  number    label
0           1     100     Math
1           2      50  Science
2           3      20  History

名義尺度の数値化方法

Label Encoding

「Label Encoding」は「scikit-learn」にある「LabelEncoder」というクラスを使用することで簡単に変換できます。

from sklearn.preprocessing import LabelEncoder
lab = LabelEncoder()
lab = lab.fit(df['label'])
df['label'] = lab.transform(df['label'])

「LabelEncoding」は後述する「One hot Encoding」に対して、新しく作成される変数は1つです。これはData数が多くならずに済むメリットがあります。

逆にデメリットとしては、数値の大小に意味がないので、ロジスティック回帰等には不向きな変換方法となります。

【結果】

   evaluation  number  label
0           1     100      1
1           2      50      2
2           3      20      0

One Hot Encoding

「One Hot Encoding」はダミー変数化ともいい、カテゴリの数だけ変数を作成して該当するか否かで0,1のテーブルを作成します。

One Hot Encodingは「scikit-learn」の「OneHotEncoder」クラスを用いることで簡単に変換できますが、ここでは、便宜上「category_encoders」を用いています。


import category_encoders as cat_en
list_cols = ['label']
#1--列指定
oneh = cat_en.OneHotEncoder(cols=list_cols)#encoderの生成
oneh_out = oneh.fit_transform(df[list_cols])#実行
out = pd.concat([df, oneh_out], axis=1)#元のdataと結合

One Hot Encodingは非常にシンプルな数値変換になります。

デメリットはカテゴリの数だけ変数を作成して0,1を振っていくため、列が増えてしまいます。また、線形回帰などでは変数同士の相関が高くなり、多重共線性の問題が出てしまうのも特徴です。

【結果】

   evaluation  number    label  label_1  label_2  label_3
0           1     100     Math        1        0        0
1           2      50  Science        0        1        0
2           3      20  History        0        0        1

このままでは余計な情報が多いので、「label」列を削除したり、列名を変換して分かりやすくする必要があります。

「get_dummies」→列情報を整理

df_dummy = pd.get_dummies(df[list_cols])
out = pd.concat([df.drop(['label'],axis=1),df_dummy],axis=1)

上記では、label列をダミー変数化して、元のDataFrameに結合しています。

【結果】

   evaluation  number  label_History  label_Math  label_Science
0           1     100              0           1              0
1           2      50              0           0              1
2           3      20              1           0              0

「label」列の削除と列名を変換できていることが確認できました。次に、多重共線性を回避するために列要素を1つ削除します。これは「get_dummies」で「drop_first = True」とするだけで最初の列を削除できます。

df_dummy = pd.get_dummies(df[list_cols],drop_first = True)
out = pd.concat([df.drop(['label'],axis=1),df_dummy],axis=1)

【結果】

  evaluation  number  label_Math  label_Science
0           1     100           1              0
1           2      50           0              1
2           3      20           0              0

削除してもDataの欠損にならない理由としては「label_Math」「label_Science」がともに0の場合は「label_History」であることが分かるからです。

Count Encoding

「Count Encoding」はデータに含まれるカテゴリ変数の出現回数を数えたものになります。

pcategory_encodersの「CountEncoder」を用いて簡単に割り当てることができます。

import pandas as pd
import numpy as np
from category_encoders import CountEncoder
df = pd.DataFrame([
        ['A', 100, 'Math'],
        ['B', 50, 'Science'],
        ['C', 20, 'History'],
        ['A', 80, 'Math']])
df.columns = ['evaluation', 'number', 'label']
change_eva = {'A': 1, 'B': 2, 'C': 3}
df['evaluation'] = df['evaluation'].map(change_eva)

col = 'label' 
encoder = CountEncoder()
encoder.fit(df[col])
df['%s_count'%col] = encoder.transform(df[col])

列を指定して、頻度を算出しています。

デメリットは異なるカテゴリカル変数に同じ値が割り当てられ、情報が失われる場合があることです。今回だったら、ScienceとHistoryが1になっていることです。

【結果】

   evaluation  number    label  label_count
0           1     100     Math            2
1           2      50  Science            1
2           3      20  History            1
3           1      80     Math            2

最後に

それぞれEncodingにも特徴があることが分かります。

Dataをよく観察してからEncoding方法を決定する必要がありますね。

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