分類アルゴリズムの基礎:不均衡データへのSMOTE適用

分類アルゴリズムの概要

分類アルゴリズムは、教師あり学習における主要な手法の一つです。その目的は、入力されたデータをあらかじめ定義された複数のクラス(カテゴリ)に割り当てることです。例えば、受信したメールを「迷惑メール」と「通常メール」に分類するのは典型的な二値分類のタスクであり、一方で、料理の材料情報からその料理がどの国の料理であるかを予測するのは、多クラス分類のタスクに該当します。

回帰が連続的な数値を予測するのに対し、分類は離散的なクラスラベルを予測します。この記事では、多クラス分類の具体例として、様々な料理の材料データセットを用いて、その料理の国籍を特定するモデルを構築するプロセスを解説します。

ロジスティック回帰:名前の裏にある真実

「回帰」という名前がついていますが、ロジスティック回帰は実際には分類問題に広く用いられるアルゴリズムです。その核心は、線形な出力をシグモイド関数と呼ばれるS字型の関数を通して0から1の間の確率値に変換することにあります。例えば、この確率値が0.5を超えれば「クラスA」、0.5以下であれば「クラスB」といったように、しきい値を設定してデータを二つのカテゴリに分類します。この仕組みにより、ロジスティック回帰は分類タスクを効率的に実行できるのです。

データの準備と前処理

機械学習モデルの性能は、データの質に大きく左右されます。ここでは、料理の国籍を分類するためのデータセットを準備し、分析に適した形に整えるプロセスを説明します。前処理の主なステップには、不要なデータの削除、特徴量の選択、そして重要な「データの均衡化」が含まれます。

データの読み込みと初期確認

まずは、必要なライブラリをインポートし、データセットを読み込みます。


import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from imblearn.over_sampling import SMOTE

# データセットの読み込み
raw_data_df = pd.read_csv('dish_data.csv')
raw_data_df.head()

このデータセットは、各料理が特定の材料を含むかどうかを0と1で表現しています。'cuisine'列が目標変数(料理の国籍)です。

次に、各国籍の料理データがどの程度存在するかを確認します。これはデータの不均衡を把握する最初のステップです。


# 国籍ごとのデータ数を棒グラフで可視化
raw_data_df['cuisine'].value_counts().plot(kind='barh', title='Distribution of Cuisines')
plt.xlabel('Number of Samples')
plt.show()

このグラフから、特定の国籍のデータが他に比べて非常に多い(または少ない)ことがわかります。このような不均衡は、モデルが多数派のクラスを過剰に学習し、少数派のクラスを無視してしまう原因となるため、対処が必要です。

特徴量の選択とデータのクレンジング

モデルの精度を向上させるためには、各クラスを区別する上で有益でない特徴量を削除することが有効です。例えば、多くの国の料理で共通して使われるような材料(この例では「米」「にんにく」「生姜」など)は、国籍を特定する上での識別力が低いと考えられます。

まず、各料理カテゴリで頻繁に使われる材料を特定します。


def get_top_ingredients(data, n=10):
    """各国籍で最も使用頻度の高い材料を上位n件取得する関数"""
    cuisine_data = data.drop(columns=['cuisine', 'id'])
    ingredient_counts = cuisine_data.sum().sort_values(ascending=False)
    return ingredient_counts.head(n)

# 各国籍の上位材料を確認
for cuisine in raw_data_df['cuisine'].unique():
    cuisine_subset = raw_data_df[raw_data_df['cuisine'] == cuisine]
    top_ingredients = get_top_ingredients(cuisine_subset)
    print(f"\nTop 10 ingredients in {cuisine} cuisine:")
    top_ingredients.plot.barh(title=f'Common Ingredients in {cuisine} Cuisine')
    plt.show()

可視化の結果、「rice」「garlic」「ginger」は多くの料理カテゴリで頻繁に使用されていることが確認できます。これらは分類のノイズになりうるため、特徴量から除外します。


# 不要な列と識別力の低い材料を削除
columns_to_drop = ['cuisine', 'id', 'rice', 'garlic', 'ginger']
ingredient_matrix = raw_data_df.drop(columns=columns_to_drop)

# 目的変数(国籍ラベル)を分離
cuisine_labels = raw_data_df['cuisine']

ingredient_matrix.head()

これで、モデルの学習に使用する特徴量マトリックスと、予測すべきラベルが準備できました。しかし、データの不均衡問題はまだ解決されていません。

データの均衡化とSMOTEの適用

データ不均衡問題を解決するための高度な手法の一つに、SMOTE(Synthetic Minority Over-sampling Technique)があります。SMOTEは、少数派クラスのデータ点をただ単純に複製するのではなく、既存の少数派データ点同士の特徴空間内で新しい合成データ点を作り出すことでデータを増強します。これにより、少数派クラスの多様性を保ちながらデータを均衡化できます。

SMOTEによるデータ増強

それでは、SMOTEを適用してデータセットを均衡化させてみましょう。


# SMOTEの初期化と適用
smote_sampler = SMOTE(random_state=42)

# 特徴量とラベルをリサンプリング
balanced_ingredients, balanced_cuisines = smote_sampler.fit_resample(ingredient_matrix, cuisine_labels)

SMOTEの適用後、各クラスのデータ数が均等になっていることを確認します。


# 均衡化後のデータ分布を可視化
print("Data distribution after balancing:")
balanced_distribution = pd.Series(balanced_cuisines).value_counts()
print(balanced_distribution)

balanced_distribution.plot(kind='barh', title='Balanced Cuisine Distribution after SMOTE')
plt.xlabel('Number of Samples')
plt.show()

グラフから、すべての料理の国籍のサンプル数が、最も多かったクラスの数に合わせて増加し、完全に均等になっていることがわかります。これで、モデルが特定の国籍に偏ることなく、すべてのクラスを公平に学習できる準備が整いました。この前処理済みのデータセットを用いて、次のステップで分類モデルの構築と訓練を行います。

タグ: 機械学習 分類アルゴリズム SMOTE データ前処理 Pandas

6月8日 00:13 投稿