機械学習データ前処理入門

機械学習のためのデータ前処理:カテゴリ変数を適切に扱う方法【Pandas入門】

Tags: データ前処理, カテゴリ変数, エンコーディング, Pandas, Python

はじめに

機械学習モデルを構築する際には、分析対象のデータをモデルが理解できる形式に整える「データ前処理」という重要なステップがあります。データ前処理は、モデルの性能に大きく影響するため、非常に大切です。

これまでの記事では、欠損値や外れ値といったデータの問題に対処する方法について解説しました。今回は、カテゴリ変数と呼ばれる種類のデータを、機械学習モデルが扱えるように変換する方法に焦点を当てて解説します。

多くの機械学習アルゴリズムは、入力データが数値であることを前提としています。しかし、私たちが扱うデータには、「性別」や「出身地」、「商品カテゴリ」のように、文字列や区分で表されるデータが含まれることがよくあります。このようなカテゴリ変数を適切に処理せずにモデルに入力すると、エラーが発生したり、モデルがデータを正しく解釈できなかったりします。

この記事では、カテゴリ変数とは何かを改めて確認し、なぜ数値に変換する必要があるのか、そして代表的な変換手法である「One-Hot Encoding」と「Label Encoding」について、Pythonの代表的なデータ分析ライブラリであるPandasを使った具体的な実装方法を交えて解説します。データ前処理の次のステップとして、ぜひ本記事の内容を学んでいきましょう。

カテゴリ変数とは

カテゴリ変数とは、データをいくつかの「カテゴリ」や「分類」に分けられる変数です。数値として計算できる連続的なデータ(例:身長、価格)とは異なり、カテゴリ変数はその属性や種類を表します。

例えば、以下のようなデータ項目がカテゴリ変数に該当します。

カテゴリ変数には、大きく分けて二つの種類があります。

  1. 名義尺度 (Nominal Scale): カテゴリ間に順序や大小関係がないもの。「性別」や「出身地」、「血液型」、「商品の色」などがこれに該当します。カテゴリは単なる区別のためにつけられた名前のようなものです。
  2. 順序尺度 (Ordinal Scale): カテゴリ間に順序や大小関係があるもの。「アンケートの評価」(悪い < 普通 < 良い)や、「衣服のサイズ」(S < M < L)などがこれに該当します。カテゴリには明確な順番が存在します。

これらのカテゴリ変数を、機械学習モデルが理解できる数値形式に変換する必要があります。

なぜカテゴリ変数を数値化する必要があるのか

ほとんどの機械学習モデルは、数学的な計算に基づいてデータを処理します。例えば、距離を計算したり、勾配降下法のような最適化手法を用いたりします。これらの計算は、数値データに対して行われることが前提です。

文字列で表現されたカテゴリデータ(例: "東京都", "大阪府")は、そのままでは数学的な計算ができません。機械学習モデルに「東京都」と「大阪府」を入力しても、モデルはそれらの間にどのような関係性があるのか、数値としてどのくらいの「距離」があるのかを理解できません。

そのため、カテゴリ変数を、モデルが計算可能な数値表現に変換する必要があります。この変換プロセスのことを「エンコーディング (Encoding)」と呼びます。

代表的なカテゴリ変数エンコーディング手法

カテゴリ変数を数値にエンコードする手法はいくつか存在しますが、ここでは最も一般的で基本的な二つの手法をご紹介します。

  1. One-Hot Encoding (ワンホットエンコーディング)
  2. Label Encoding (ラベルエンコーディング)

それぞれの概念とPandasを使った実装方法を見ていきましょう。

One-Hot Encoding (ワンホットエンコーディング)

One-Hot Encodingは、名義尺度のような順序を持たないカテゴリ変数を扱う際によく用いられる手法です。この手法では、元のカテゴリ変数の各カテゴリに対して、新しい列(特徴量)を作成します。そして、元のデータがどのカテゴリに属するかを、そのカテゴリに対応する新しい列に「1」、それ以外の列に「0」を設定することで表現します。

例えば、「出身地」というカテゴリ変数があり、「東京」「大阪」「福岡」という3つのカテゴリが含まれているとします。One-Hot Encodingを行うと、元の「出身地」列の代わりに、「出身地_東京」「出身地_大阪」「出身地_福岡」という3つの新しい列が作成されます。

このように、データがどのカテゴリに属するかを「1つだけがHot(オン)になっている」状態で表現するため、One-Hotと呼ばれます。

Pandasでの実装例 (get_dummies 関数)

Pandasライブラリには、One-Hot Encodingを簡単に行うための get_dummies 関数が用意されています。

まず、サンプルデータを用意しましょう。

import pandas as pd

data = {'ID': [1, 2, 3, 4, 5],
        '性別': ['男性', '女性', '男性', '女性', '男性'],
        '出身地': ['東京', '大阪', '福岡', '東京', '大阪'],
        '評価': ['良い', '普通', '悪い', '良い', '普通']}
df = pd.DataFrame(data)

print("--- 元のデータフレーム ---")
print(df)
--- 元のデータフレーム ---
   ID  性別 出身地  評価
0   1  男性  東京  良い
1   2  女性  大阪  普通
2   3  男性  福岡  悪い
3   4  女性  東京  良い
4   5  男性  大阪  普通

このデータフレームに対して、「出身地」列をOne-Hot Encodingしてみましょう。

# '出身地' 列に対して One-Hot Encoding を適用
df_one_hot = pd.get_dummies(df, columns=['出身地'])

print("\n--- One-Hot Encoding 適用後のデータフレーム(出身地列) ---")
print(df_one_hot)
--- One-Hot Encoding 適用後のデータフレーム(出身地列) ---
   ID  性別  評価  出身地_大阪  出身地_東京  出身地_福岡
0   1  男性  良い       0       1       0
1   2  女性  普通       1       0       0
2   3  男性  悪い       0       0       1
3   4  女性  良い       0       1       0
4   5  男性  普通       1       0       0

get_dummies 関数に columns=['対象列名'] を指定することで、指定した列だけをOne-Hot Encodingできます。元の「出身地」列が削除され、代わりに「出身地_カテゴリ名」という新しい列が追加されたことがわかります。各行では、元の出身地に対応する列だけが1になっています。

get_dummies 関数は、デフォルトでは数値型以外の全ての列に対してOne-Hot Encodingを試みます。特定の列だけを対象としたい場合は、上記のように columns 引数で指定するのが便利です。

One-Hot Encodingは、カテゴリ間の順序関係をモデルに誤って学習させないという利点がありますが、カテゴリの種類が多い場合には新しい列が大量に生成され、データの次元が非常に高くなる(特徴量の数が増える)という欠点があります。これは「次元の呪い」と呼ばれ、モデルの学習効率が悪化したり、過学習を招いたりする可能性があります。

Label Encoding (ラベルエンコーディング)

Label Encodingは、カテゴリ変数に含まれる各カテゴリに、0から始まる一意の整数値を割り当てる手法です。例えば、「評価」というカテゴリ変数があり、「悪い」「普通」「良い」というカテゴリが含まれているとします。Label Encodingを行うと、以下のように数値が割り当てられる可能性があります。

この手法は非常にシンプルで、新しい列が増えないため次元の呪いを避けることができます。しかし、割り当てられた数値(例: 0, 1, 2)の間に、そのまま数学的な順序や大小関係が存在するとモデルが解釈してしまう可能性があります。

このため、Label Encodingは主に順序尺度のカテゴリ変数に対して使用するのが適しています。例えば、「悪い」<「普通」<「良い」のように順序に意味がある場合に、その順序を反映するように数値(0, 1, 2)を割り当てることで、モデルが順序関係を学習できるようになります。

名義尺度(順序に意味がない)の変数にLabel Encodingを使用すると、例えば「男性=0」「女性=1」とした場合に、モデルが「女性は男性より大きい/小さい」といった誤った解釈をする可能性があります。

Pandasでの実装例 (.astype('category').cat.codes)

Pandasでは、DataFrameのカテゴリ型機能を利用してLabel Encodingと同様の処理を行うことができます。

先ほどのサンプルデータフレーム df を再び使用します。今回は「評価」列に対してLabel Encodingを適用してみましょう。「評価」は「悪い < 普通 < 良い」という順序があるため、Label Encodingが適しています。

# '評価' 列をカテゴリ型に変換し、そのコードを取得
df['評価_encoded'] = df['評価'].astype('category').cat.codes

print("\n--- Label Encoding 適用後のデータフレーム(評価列) ---")
print(df)
--- Label Encoding 適用後のデータフレーム(評価列) ---
   ID  性別 出身地  評価  評価_encoded
0   1  男性  東京  良い           2
1   1  男性  東京  良い           2
1   2  女性  大阪  普通           1
2   3  男性  福岡  悪い           0
3   4  女性  東京  良い           2
4   5  男性  大阪  普通           1

.astype('category') で列をカテゴリ型に変換し、.cat.codes で各カテゴリに割り当てられた整数値を取得しています。Pandasは内部的にカテゴリを一意の整数値にマッピングします。デフォルトでは、カテゴリが出現した順番やアルファベット順などで数値が割り当てられます。もし特定の順序で割り当てたい場合は、カテゴリ型に変換する際に categories 引数で順序を指定することも可能です。

上記例では、「悪い」が0、「普通」が1、「良い」が2と割り当てられています。これは、Pandasが内部でカテゴリを一意のコードに変換した結果であり、順序尺度の意図と合致しています。

Label Encodingはシンプルで次元が増えないというメリットがありますが、名義尺度に使うとモデルに誤った順序関係を学習させてしまうリスクがあることを理解しておくことが重要です。

どちらの手法を選ぶべきか

カテゴリ変数のエンコーディング手法を選択する際は、以下の点を考慮します。

ビジネスの現場で初めてデータ前処理を行う際には、まず名義尺度にはOne-Hot Encoding、順序尺度にはLabel Encodingを試してみるのが良いスタート地点となります。

まとめ

この記事では、機械学習モデルが数値データを必要とする理由から、カテゴリ変数を適切に扱うための基本的なエンコーディング手法であるOne-Hot EncodingとLabel Encodingについて解説しました。

データ前処理は機械学習プロジェクトの成功に不可欠なステップであり、カテゴリ変数の適切な処理はその中でも重要な位置を占めます。今回学んだ基本的な手法を理解し、ご自身のデータに適用できるようになることが、データ前処理スキル習得の大きな一歩となります。

データには様々な種類があり、カテゴリ変数以外にも数値データのスケーリングなど、検討すべき前処理は他にもあります。本サイトでは引き続き、機械学習のためのデータ前処理について体系的に解説していく予定です。ぜひ他の記事も参考にして、データ前処理の知識を深めていってください。