はじめに
前回の記事では、料理データセットの前処理(クリーニングとバランシング)を完了しました。今回は、複数の分類アルゴリズムを用いてモデルを構築し、特定の材料の組み合わせから料理の国籍を予測するタスクに取り組みます。この過程で、異なる分類アルゴリズムの評価と比較を行い、タスクに最適なモデルを選択する方法を学びます。
分類アルゴリズムの選択
Scikit-learnは教師あり学習の一部として分類タスクを扱い、様々な分類アルゴリズムを提供しています。主な選択肢は以下の通りです:
- 線形モデル (Linear Models): 線形の仮定に基づき、特徴量の線形結合によって分類を行います。
- サポートベクターマシン (Support Vector Machines): クラス間のマージンを最大化する最適な分離超平面を見つけることで分類を実現します。
- 確率的勾配降下法 (Stochastic Gradient Descent): 大規模なデータセットを効率的に処理できる最適化手法です。
- k近傍法 (Nearest Neighbors): インスタンスベースの学習法で、サンプル間の距離計算に基づいて分類します。
- ガウス過程 (Gaussian Processes): 非パラメトリックなベイズ手法で、データの潜在的な分布を捉えて分類します。
- 決定木 (Decision Trees): 木構造を構築し、特徴量の値に基づいて段階的にデータを分割します。
- アンサンブル法 (投票分類器) (Ensemble methods - voting classifier): 複数の分類器の予測結果を組み合わせて、全体の分類性能を向上させます。
- 多クラス・多出力アルゴリズム (Multiclass and multioutput algorithms): 多クラス分類や多ラベル分類の問題を扱います。
今回のタスクは、予測対象が固定された多クラス分類問題です。ニューラルネットワークは強力ですが、データセットが小規模で比較的クリーンなため、過剰に複雑です。決定木とロジスティック回帰が適切な候補となります。決定木は直感的で解釈が容易ですが、ロジスティック回帰は多クラスデータにおいてクラス間の線形関係を効果的にモデル化できます。最終的に、ロジスティック回帰を採用することにしました。
ロジスティック回帰の詳細
Scikit-learnのLogisticRegressionを使用する際、multi_classとsolverの2つのパラメータがモデルの挙動と性能に直接影響を与えるため、特に注意が必要です。
| パラメータ | 説明 | 選択可能な値 | 備考 |
|---|---|---|---|
multi_class | 分類方式を指定します。 | ovr (One-vs-Rest)multinomial | ovrはデフォルトで、二値分類および多クラス分類に適しています。multinomialは多クラス分類に適し、ソフトマックス出力を伴うことが一般的です。 |
solver | ロジスティック回帰モデルの重みを求める最適化アルゴリズムを選択します。 | liblinearnewton-cglbfgssagsaga | liblinearはovrとのみ互換性があります。newton-cg、lbfgs、sag、sagaはmultinomialと組み合わせて使用できます。 |
One-vs-Rest (OvR) 戦略の詳細
OvR戦略は、多クラス分類問題を複数の二値分類問題に分解する方法です。各クラスに対して、そのクラス(正クラス)と他のすべてのクラス(負クラス)を区別する二値分類器を訓練します。例えば、「赤」「青」「緑」の3クラス分類問題の場合、以下の3つの二値分類問題が作成されます:
- サンプルが「赤」かどうかを「青」と「緑」から区別する。
- サンプルが「青」かどうかを「赤」と「緑」から区別する。
- サンプルが「緑」かどうかを「赤」と「青」から区別する。
元来二値分類用に設計されたロジスティック回帰を、この戦略によって多クラス分類に適用することができます。
データの分割
前処理済みのデータセットを読み込み、訓練データとテストデータに分割します。
import pandas as pd
from sklearn.model_selection import train_test_split
# データの読み込み
data_frame = pd.read_csv("../../data/cleaned_cuisines.csv")
# 特徴量とラベルの分離
labels = data_frame['cuisine']
features = data_frame.drop(columns=['cuisine'])
# データを訓練セットとテストセットに分割 (70%訓練, 30%テスト)
X_train_set, X_test_set, y_train_set, y_test_set = train_test_split(
features, labels, test_size=0.3, random_state=42
)
モデルの構築と評価
ロジスティック回帰モデルを構築し、その性能を評価します。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report, accuracy_score
import numpy as np
# ロジスティック回帰モデルのインスタンス化と訓練
classifier = LogisticRegression(multi_class='ovr', solver='liblinear')
classifier.fit(X_train_set, np.ravel(y_train_set))
# テストデータでの予測と正解率の計算
predictions = classifier.predict(X_test_set)
model_accuracy = accuracy_score(y_test_set, predictions)
print(f"モデルの正解率: {model_accuracy:.4f}")
# 詳細な分類レポートの出力
print("\n分類レポート:")
print(classification_report(y_test_set, predictions))
上記コードを実行すると、約80%の正解率が得られました。分類レポートは、各クラスごとの適合率 (precision)、再現率 (recall)、F1スコアを詳細に示し、モデルの強みと弱みを理解するのに役立ちます。
個別サンプルの予測確率
特定のテストサンプルに対する各クラスの予測確率を確認することもできます。
# テストセットの50番目のサンプルに対する予測確率を取得
sample_idx = 50
test_sample = X_test_set.iloc[sample_idx].values.reshape(1, -1)
prediction_probabilities = classifier.predict_proba(test_sample)
# 確率をデータフレームに変換して表示
probability_df = pd.DataFrame(data=prediction_probabilities,
columns=classifier.classes_)
# 確率の降順でソートして上位を表示
sorted_predictions = probability_df.T.sort_values(by=0, ascending=False)
print("各料理カテゴリの予測確率:")
print(sorted_predictions.head())
この出力から、モデルがそのサンプルをどのクラスに最も強く関連付けているかを確認できます。