注目キーワード
  1. Python
  2. コンペ

【Python初心者向け】機械学習の二値分類入門|scikit-learnで実装する完全ガイド

この記事で学べること

  • 機械学習の二値分類の基本概念と実装方法
  • Pythonとscikit-learnを使った実践的なコーディング
  • データ前処理から評価まで一連の流れ
  • 複数の分類手法の比較と選び方
  • 実務で使える評価指標の使い分け

対象読者

  • Pythonの基本文法を理解している方
  • 機械学習を始めたい初心者
  • データ分析の実務で二値分類を使いたい方
  • scikit-learnの使い方を体系的に学びたい方

この記事では、二値分類の機械学習モデル作成の基本的な流れを解説します。データの理解から始め、特徴量の選択、モデルの作成と学習、そしてモデルの評価まで、一連のステップを具体的なコード例とともに説明します。この記事に沿って進めれば、最低限の二値分類モデルを作成し、評価することができるようになるはずです。

二値分類とは?具体例で理解する

二値分類とは、機械学習の一種で、ある入力が特定の2つのクラスのどちらに属するかを予測するタスクです。例えば、メールがスパムかどうか、画像が犬か猫か、患者が病気か健康かなどを判断することができます。

二値分類の身近な例

  1. スパムメール判定: 受信メールが「スパム」か「正常」か
  2. 顧客離反予測: 顧客が「継続利用」か「解約」か
  3. 病気診断: 患者が「健康」か「病気」か
  4. 画像判定: 写真が「犬」か「猫」か
  5. 融資審査: 申し込み者が「承認」か「却下」か
  6. 品質管理: 製品が「良品」か「不良品」か

他の機械学習タスクとの違い

  • 多クラス分類: 3つ以上のクラスに分類(例: 花の種類分類)
  • 回帰: 連続値を予測(例: 売上予測、気温予測)
  • クラスタリング: ラベルなしでデータをグループ化

なお、pandasなどのライブラリについての入門知識や、機械学習に関する基本的な用語(特徴量など)は知っている前提で記事を書いていますのでご了承ください。

主要な二値分類手法の比較

二値分類には様々な手法があります。それぞれの特徴を理解して、問題に適した手法を選ぶことが重要です。

手法 特徴 メリット デメリット 適用場面
ロジスティック回帰 線形モデル 解釈しやすい、高速、安定 非線形関係を捉えにくい ベースライン、解釈重視
決定木 ルールベース 直感的、可視化可能 過学習しやすい 説明性重視、ルール抽出
ランダムフォレスト アンサンブル 安定、特徴量重要度算出 メモリ消費大、解釈困難 バランス重視、実用性
SVM マージン最大化 高次元データに強い パラメータ調整が困難 高次元データ、小規模
XGBoost/LightGBM 勾配ブースティング 高精度、特徴量重要度 調整が複雑、時間かかる コンペ、高精度要求

初心者におすすめの学習順序

  1. ロジスティック回帰: 線形モデルの基本理解
  2. 決定木: 可視化でモデルの動作理解
  3. ランダムフォレスト: アンサンブル学習の実用性体験
  4. LightGBM: 最新の高性能手法を体験

データの確認と理解

基本統計量の確認

機械学習モデルを作成する前に、まずは使用するデータを理解することが重要です。データの理解を深めるためには、基本統計量の確認が有効です。Pythonのpandasライブラリを使用すると、データの基本統計量を簡単に確認することができます。

まずは、data.describe()を使用して、データの基本統計量を確認します。これにより、データの個数(count)、平均値(mean)、標準偏差(std)、最小値(min)、第一四分位数(25%)、中央値(50%)、第三四分位数(75%)、最大値(max)を一度に確認することができます。

# 数値データの基本統計量
print(df.describe())

# カテゴリデータの統計量
print(df.describe(include=['O']))

# データの型の表示
print(df.dtypes)

# 欠損値の確認
print(df.isnull().sum())

また、オブジェクト型のデータについても確認することが可能です。data.describe(include=['O'])を使用すると、オブジェクト型のデータの個数(count)、ユニークな要素の個数(unique)、最も多く出現する要素(top)、最頻値の出現回数(freq)を確認できます。

これらの情報を利用することで、データの全体像を把握し、どの特徴量が重要そうか、また、欠損値や異常値がないかなど、データの品質を確認することができます。これは、後の特徴量選択やモデルの選択に大いに役立ちます。

データ型の確認

各カラムの型についても確認し、必要であれば変換します。

特に日付型についてはpandas読み込み時に自動的に文字列型になってしまうので、日時型への変換を行います。

なお、型の確認はデータフレーム.dtypes、日時型への変換はpd.to_datetime[“カラム名”]で可能です。

# データの型の表示
print(df.dtypes)

# 日時型への変換
df["AAA"] = pd.to_datetime(df["AAA"])

# データの型の表示
print(df.dtypes)

データの可視化と相関の確認

データの理解を深めるためには、データの可視化が非常に有効です。また、特徴量間の相関を確認することで、特徴量の選択やモデルの作成に役立つ情報を得ることができます。

まず、クロス集計を行います。クロス集計は、2つのカテゴリ変数の関係を表形式で表示することで、変数間の関係を理解するのに役立ちます。pandasのpd.crosstab()関数を使用すると、簡単にクロス集計を行うことができます。例えば、カラムAAAと目的変数yのクロス集計を行いたい場合、以下のようにします。

pd.crosstab(df['AAA'], df['y'], margins=True)

各カラムとyとの関係を全体に占めるy=1の割合として棒グラフで比較するようなことも可能です。

import matplotlib.pyplot as plt

# カラム名のリストを作成
columns = ['AAA', 'BBB', 'CCC', 'DDD', 'EEE', 'FFF']

# 各カラムについてループを回す
for column in columns:
    # pd.crosstabを使ってカラムと'y'の関係を計算
    cross_tab = pd.crosstab(df[column], df['y'], normalize='index')
    
    # 比率を棒グラフで表示
    cross_tab.plot(kind='bar', stacked=True, figsize=(10, 5))
    
    # グラフのタイトルを設定
    plt.title(f"Proportion of y=1 in each category of {column}")
    
    # グラフを表示
    plt.show()

次に、量的データの相関を計算し、ヒートマップで可視化します。これにより、特徴量間の相関関係を一目で確認できます。以下のようにdf.corr()で相関行列を計算し、seabornのsns.heatmap()関数でヒートマップを作成します。

# 相関行列の計算
corr_matrix = df.corr()

# ヒートマップの作成
sns.heatmap(corr_matrix, cmap="Reds")

さらに、目的変数yが0の場合と1の場合で、各特徴量のヒストグラムを作成します。これにより、特徴量が目的変数にどのように影響しているかを視覚的に理解することができます。以下のようにしてヒストグラムを作成します。

# 必要なライブラリのインポート
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# データの読み込み
data = pd.read_csv('train.csv', index_col='id')

# 'y'の値によって特定の特徴量のデータを分割
feature_when_y_is_0 = data[data['y']==0]['feature']
feature_when_y_is_1 = data[data['y']==1]['feature']

# ヒストグラムの作成
sns.distplot(feature_when_y_is_0, label='y=0')
sns.distplot(feature_when_y_is_1, label='y=1')

# グラフのタイトル、軸ラベルの設定
plt.title('Feature Histogram')
plt.xlabel('Feature')
plt.ylabel('Frequency')

# x軸の表示範囲の指定
plt.xlim(0, 2000)

# グラフの凡例を追加
plt.legend()

# グラフの表示
plt.show()

これにより、特徴量が目的変数にどのように影響しているかを視覚的に理解することができます。特に、目的変数が0と1で特徴量の分布が大きく異なる場合、その特徴量は予測モデルの作成において重要な役割を果たす可能性があります。

特徴量の選択と前処理

機械学習モデルの性能は、適切な特徴量を選択し、それらを適切に前処理することで大きく向上します。特徴量の選択では、目的変数との相関が高い特徴量や、ビジネス的な観点から重要と考えられる特徴量を選択します。また、特徴量が多すぎるとモデルの学習が難しくなるため、不要な特徴量は削除します。

特徴量の前処理では、欠損値の補完、外れ値の処理、スケーリング(特徴量の尺度を揃えること)、カテゴリ変数のエンコーディングなどを行います。これらの前処理は、モデルの性能を向上させ、過学習を防ぐために重要です。

特に、カテゴリ変数のエンコーディングは、機械学習モデルが理解できる形式にデータを変換するために必要です。カテゴリ変数は、通常、テキストデータ(例:’晴れ’, ‘曇り’, ‘雨’などの天気データ)であり、これをそのままモデルに入力することはできません。そこで、ダミー変数化という手法を用いて、カテゴリ変数を数値データに変換します。

ダミー変数化は、各カテゴリを表す新しいカラムを作成し、そのカテゴリに該当する行には1を、それ以外の行には0を入れる方法です。pandasのget_dummies()関数を使用すると、簡単にダミー変数化を行うことができます。例えば、カラムAAAをダミー変数化するには以下のようにします。

pd.get_dummies(df['AAA'])

これにより、カラムAAAの各カテゴリが新しいカラムとして作成され、各行には該当するカテゴリに1、それ以外に0が入ります。このようにして、カテゴリ変数をモデルが理解できる形式に変換します。

以上の特徴量の選択と前処理を行うことで、モデルの学習がスムーズに進み、より高い性能のモデルを作成することが可能になります。

モデルの作成と学習

機械学習モデルの作成と学習は、データ分析の中心的なプロセスです。このステップでは、まず目的変数と特徴量を定義し、次にデータを学習用と評価用に分けます。その後、選択したモデルを用いて学習を行い、最後にモデルの性能を評価します。

目的変数と特徴量

まず、入力データを目的変数yと特徴量Xに分解します。以下はy以外のカラムをすべて特徴量として使用する例です。

# data_yに目的変数を代入
data_y = df['y']

# data_Xに説明変数を代入
data_X = df.drop('y', axis=1)

学習データと評価データの分割

次にデータを学習用と評価用に分けます。scikit-learnのtrain_test_split関数を使い、データをランダムに分割します。分割比率は調整可能で、一般的には学習データ:評価データを7:3~8:2にすることが多いです。以下は3:1にした例です。

# 学習データと評価データにデータを分割
train_X, test_X, train_y, test_y = train_test_split(data_X, data_y, test_size=0.25, random_state=0)

モデルの選択と学習

scikit-learnから使用するモデルをimportし、パラメータの設定→学習という流れで進めます。以下の通りライブラリのおかげで簡単に実装はできます。

モデルは色々と種類がありテーマによって選択するものは異なりますが、ここでは私が記事作成時にちょうど学んだばかりである「決定木」を使用します。

なお、実際にはこの決定木を組み合わせた「勾配ブースティングモデル」である「LightGBM」を使用すると良い結果が出ることが多いので、迷ったらまずはLightGBMを使用してみると良いと思います。

# 決定木モデルのインポート
from sklearn.tree import DecisionTreeClassifier as DT

# 決定木モデルの準備
tree = DT(max_depth = 2, random_state = 0)

# 決定木モデルの学習
tree.fit(train_X, train_y)

決定木モデルの場合、特徴量の重要度を確認することができます。これは、各特徴量がモデルの予測にどれだけ寄与しているかを示します。

# 重要度の表示
print( tree.feature_importances_ )

# 重要度に名前を付けて表示
print( pd.Series(tree.feature_importances_, index=train_X.columns) )

学習したモデルを用いて、評価用データの予測を行います。分類問題でそれぞれの分類の確率を表示するためにはpredict_probaを使います。

tree.predict_proba(test_X)[:,1]

複数手法による性能比較

実務では複数の手法を比較して最適なモデルを選択することが重要です。以下に主要な手法の比較実装例を示します。

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.metrics import roc_auc_score, classification_report

# モデル定義
models = {
    'ロジスティック回帰': LogisticRegression(random_state=42),
    '決定木': DecisionTreeClassifier(max_depth=5, random_state=42),
    'ランダムフォレスト': RandomForestClassifier(n_estimators=100, random_state=42),
    'SVM': SVC(probability=True, random_state=42)
}

# 各モデルの学習と評価
results = {}
for name, model in models.items():
    print(f"\n=== {name} ===")
    
    # 学習
    model.fit(train_X, train_y)
    
    # 予測
    y_pred = model.predict(test_X)
    y_pred_proba = model.predict_proba(test_X)[:, 1]
    
    # 評価
    auc = roc_auc_score(test_y, y_pred_proba)
    results[name] = auc
    
    print(f"AUC: {auc:.4f}")
    print(classification_report(test_y, y_pred))

# 結果の比較
print("\n=== モデル性能比較 ===")
for name, auc in sorted(results.items(), key=lambda x: x[1], reverse=True):
    print(f"{name}: AUC = {auc:.4f}")
/

モデルの評価

モデルの学習が完了したら、次にその性能を評価します。ここでは、AUC(Area Under the Curve)を計算し、ROC(Receiver Operating Characteristic)曲線を描画してモデルの性能を視覚的に理解します。

AUCは2値分類の評価関数で、ROC曲線の面積を示し、精度が高いほど値が大きくなります。ROC曲線は真陽性率と偽陽性率の変化を示し、モデルの性能を視覚的に理解できます。

AUCの計算

まず、roc_auc_score関数を使用してAUCを計算します。この関数は、実際の値と予測値を引数に取り、AUCを計算します。

from sklearn.metrics import roc_auc_score
auc1 = roc_auc_score(test_y, pred_y1)

ROCの計算

次に、roc_curve関数を使用して偽陽性率、真陽性率、閾値を計算します。この関数は、実際の値と予測値を引数に取り、偽陽性率(FPR: False Positive Rate)、真陽性率(TPR: True Positive Rate)、閾値を返します。

from sklearn.metrics import roc_curve
fpr, tpr, thresholds = roc_curve(test_y, pred_y1)

ROC曲線の追加

最後に、matplotlibを使用してROC曲線を描画します。この曲線は、偽陽性率(FPR)をx軸、真陽性率(TPR)をy軸としてプロットしたものです。ROC曲線と対角線(ランダムな予測)を同じグラフに描画することで、モデルの性能を視覚的に理解することができます。

import matplotlib.pyplot as plt

# ROC曲線の描画
plt.plot(fpr, tpr, label='ROC curve (area = %.2f)'%auc1)

# 対角線の描画
plt.plot([0, 1], [0, 1], linestyle='--')

# グラフの各種設定
plt.title('ROC curve')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.grid(True)
plt.legend(loc='lower right')

# グラフの表示
plt.show()

以上でモデルの評価が完了です。この評価結果を元に、モデルの改善や新たな特徴量の作成などを行っていきます。

分類性能の評価指標を詳しく解説

混同行列(Confusion Matrix)

混同行列は、実際のクラスと予測クラスの組み合わせを表にしたもので、分類性能を詳細に把握できます。

from sklearn.metrics import confusion_matrix, classification_report
import seaborn as sns

# 混同行列の計算
cm = confusion_matrix(test_y, y_pred)

# 可視化
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.title('Confusion Matrix')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.show()

print("混同行列の解釈:")
print(f"True Negative (TN): {cm[0,0]} - 正しく「0」と予測")
print(f"False Positive (FP): {cm[0,1]} - 誤って「1」と予測")
print(f"False Negative (FN): {cm[1,0]} - 誤って「0」と予測")
print(f"True Positive (TP): {cm[1,1]} - 正しく「1」と予測")

主要な評価指標

指標 計算式 意味 使用場面
正解率(Accuracy) (TP+TN)/(TP+TN+FP+FN) 全体の正解率 バランスの取れたデータ
適合率(Precision) TP/(TP+FP) 予測が正の中で実際に正の割合 誤検知を避けたい場合
再現率(Recall) TP/(TP+FN) 実際に正の中で正しく予測できた割合 見逃しを避けたい場合
F1スコア 2×(Precision×Recall)/(Precision+Recall) 適合率と再現率の調和平均 バランス重視
AUC ROC曲線の面積 しきい値に依存しない総合性能 一般的な性能比較

ビジネス観点での指標選択

  • 医療診断: 再現率重視(病気の見逃しを防ぐ)
  • スパム検出: 適合率重視(正常メールの誤検知を防ぐ)
  • マーケティング: F1スコアやAUCでバランス重視
  • 金融審査: リスクに応じて適合率・再現率を調整

よくある問題と対処法

1. データ不均衡(クラスインバランス)

問題: 片方のクラスが極端に少ない(例: 正常99%、異常1%)

対処法

# クラス比率の確認
print(data_y.value_counts(normalize=True))

# 方法1: class_weightパラメータで重み付け
model_weighted = LogisticRegression(class_weight='balanced', random_state=42)

# 方法2: SMOTEでデータ拡張
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(train_X, train_y)

# 方法3: しきい値調整
from sklearn.metrics import precision_recall_curve
precision, recall, thresholds = precision_recall_curve(test_y, y_pred_proba)

# 最適なしきい値を見つける
f1_scores = 2 * (precision * recall) / (precision + recall + 1e-10)
optimal_threshold = thresholds[np.argmax(f1_scores)]
y_pred_adjusted = (y_pred_proba >= optimal_threshold).astype(int)

2. 過学習の検出と対策

問題: 訓練データに過度に適合し、新しいデータで性能が下がる

検出方法

# 学習曲線による過学習の確認
from sklearn.model_selection import learning_curve
import numpy as np

train_sizes, train_scores, val_scores = learning_curve(
    LogisticRegression(random_state=42), data_X, data_y, 
    cv=5, train_sizes=np.linspace(0.1, 1.0, 10)
)

# 可視化
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, np.mean(train_scores, axis=1), 'o-', label='Training score')
plt.plot(train_sizes, np.mean(val_scores, axis=1), 'o-', label='Validation score')
plt.xlabel('Training Set Size')
plt.ylabel('Score')
plt.title('Learning Curve')
plt.legend()
plt.grid(True)
plt.show()

対処法

  • クロスバリデーション: より信頼性の高い評価
  • 正則化: L1/L2正則化でモデルの複雑さを制御
  • 早期停止: 検証誤差が増加し始めたら学習を停止
  • データ増加: 訓練データを増やす

3. 特徴量の重要度分析

# ランダムフォレストの特徴量重要度
rf_model = RandomForestClassifier(n_estimators=100, random_state=42)
rf_model.fit(train_X, train_y)

# 重要度の可視化
feature_importance = pd.Series(
    rf_model.feature_importances_, 
    index=train_X.columns
).sort_values(ascending=False)

plt.figure(figsize=(10, 6))
feature_importance.head(10).plot(kind='bar')
plt.title('Top 10 Feature Importance')
plt.xlabel('Features')
plt.ylabel('Importance')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

# 相関の強い特徴量の特定
corr_matrix = data_X.corr().abs()
upper_triangle = corr_matrix.where(
    np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)
)

# 高相関のペアを抽出
high_corr_pairs = []
for column in upper_triangle.columns:
    high_corr = upper_triangle[column][upper_triangle[column] > 0.8]
    for idx in high_corr.index:
        high_corr_pairs.append((column, idx, high_corr[idx]))

print("高相関の特徴量ペア(相関係数 > 0.8):")
for pair in high_corr_pairs:
    print(f"{pair[0]} - {pair[1]}: {pair[2]:.3f}")

モデルの改善

モデルの評価が終わったら、次はその結果を元にモデルの改善を行います。モデルの改善には主に以下の3つの方法があります。

データを増やす

モデルの性能が思うように出ない場合、まず考えるべきはデータ量の問題です。データが少ないと、モデルが十分に学習できず、過学習や未学習の問題が生じる可能性があります。データを増やす方法としては、データの収集範囲を広げる、データの収集期間を長くする、データの補完や生成(Data Augmentation)などがあります。

アルゴリズムの変更・チューニング

使用するアルゴリズムによってもモデルの性能は大きく変わります。異なるアルゴリズムを試すことで、問題に最適なアルゴリズムを見つけることができます。また、同じアルゴリズムでもパラメータをチューニングすることで性能を向上させることが可能です。グリッドサーチやランダムサーチなどの方法を用いて最適なパラメータを探すことが一般的です。

from sklearn.model_selection import GridSearchCV

# ランダムフォレストのパラメータ最適化
param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, 10, None],
    'min_samples_split': [2, 5, 10],
    'min_samples_leaf': [1, 2, 4]
}

rf = RandomForestClassifier(random_state=42)
grid_search = GridSearchCV(rf, param_grid, cv=5, scoring='roc_auc', n_jobs=-1)
grid_search.fit(train_X, train_y)

print(f"最適パラメータ: {grid_search.best_params_}")
print(f"最高スコア: {grid_search.best_score_:.4f}")

# 最適化されたモデルで予測
best_model = grid_search.best_estimator_
y_pred_optimized = best_model.predict(test_X)
y_pred_proba_optimized = best_model.predict_proba(test_X)[:, 1]

特徴量を増やす・減らす

特徴量の選択もモデルの性能に大きく影響します。特徴量が少なすぎると、モデルが十分に学習できない可能性があります。逆に、特徴量が多すぎると、過学習の問題が生じる可能性があります。また、不要な特徴量が含まれていると、モデルの性能を下げる可能性もあります。特徴量の選択や作成は、データの理解と密接に関連しており、EDA(Exploratory Data Analysis)の結果を元に行うことが一般的です。

# 特徴量選択の例
from sklearn.feature_selection import SelectKBest, f_classif

# 上位k個の特徴量を選択
selector = SelectKBest(score_func=f_classif, k=10)
X_selected = selector.fit_transform(train_X, train_y)

# 選択された特徴量の確認
selected_features = train_X.columns[selector.get_support()]
print("選択された特徴量:")
print(selected_features.tolist())

これらの方法を組み合わせてモデルの改善を行い、最終的には問題解決につながる最適なモデルを作成します。

実務での機械学習活用事例

マーケティング分野

  • 顧客離反予測: 解約リスクの高い顧客を特定し、リテンション施策を実施
  • レスポンス予測: キャンペーンに反応する顧客を予測し、効率的な施策実行
  • 購買予測: 商品購入の可能性を予測し、パーソナライズド推薦を実現

金融分野

  • 信用審査: ローン審査の自動化と精度向上
  • 不正検知: クレジットカードの不正利用をリアルタイムで検出
  • リスク評価: 投資リスクの評価と適切なポートフォリオ構築

製造業

  • 品質管理: 不良品の自動検出と品質向上
  • 予知保全: 機械の故障を事前に予測し、ダウンタイムを最小化
  • 需要予測: 在庫最適化とサプライチェーン効率化

まとめ

以上、機械学習モデルの作成について一連の手順を記載しました。それぞれの項目で深堀りできる内容はたくさんありますが、この手順に従えば最低限のモデル作成は行えるはずです。

重要なポイントの振り返り

  • データ理解: 機械学習の成功はデータ理解から始まる
  • 適切な手法選択: 問題の特性に応じた手法を選ぶ
  • 評価指標の選択: ビジネス観点で適切な指標を使う
  • 継続的改善: 一度作って終わりではなく、継続的に改善する

次のステップ

  • 実際のデータセットでの実践
  • より高度な手法(アンサンブル学習、深層学習)の学習
  • MLOps(機械学習の運用)の理解
  • ドメイン知識の習得

機械学習は実践を通じて理解が深まります。ぜひ参考にしてください。

最新情報をチェックしよう!