はじめに
この実験では、セルフトレーニングにおける閾値の変化の影響を示します。breast_cancer データセットを読み込み、569 個のサンプルのうち 50 個だけにラベルが付けられるようにラベルを削除します。このデータセットに対して、異なる閾値を持つ SelfTrainingClassifier を適合させます。
VM のヒント
VM の起動が完了したら、左上隅をクリックして ノートブック タブに切り替えて、Jupyter Notebook を使って練習します。
Jupyter Notebook の読み込みには数秒かかる場合があります。Jupyter Notebook の制限により、操作の検証を自動化することはできません。
学習中に問題がある場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。
ライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.svm import SVC
from sklearn.model_selection import StratifiedKFold
from sklearn.semi_supervised import SelfTrainingClassifier
from sklearn.metrics import accuracy_score
from sklearn.utils import shuffle
まず、この実験に必要なライブラリをインポートします。
データの読み込み
X, y = datasets.load_breast_cancer(return_X_y=True)
X, y = shuffle(X, y, random_state=42)
y_true = y.copy()
y[50:] = -1
total_samples = y.shape[0]
breast_cancer データセットを読み込み、シャッフルします。その後、真のラベルを y_true にコピーし、y から最初の 50 個のサンプル以外のすべてのラベルを削除します。これは、半教師あり学習のシナリオをシミュレートするために使用されます。
分類器の定義
base_classifier = SVC(probability=True, gamma=0.001, random_state=42)
低いガンマ値 0.001 のサポートベクターマシン (SVM) として、基本的な分類器を定義します。
閾値の定義
x_values = np.arange(0.4, 1.05, 0.05)
x_values = np.append(x_values, 0.99999)
0.4 から 1 までの範囲で、0.05 の刻み幅で閾値の配列を定義します。その後、0.99999 という非常に高い閾値を追加して、自己ラベル付きのサンプルが生成されない閾値を含めるようにします。
結果用の配列を定義する
scores = np.empty((x_values.shape[0], n_splits))
amount_labeled = np.empty((x_values.shape[0], n_splits))
amount_iterations = np.empty((x_values.shape[0], n_splits))
実験の結果を格納するための配列を定義します。
異なる閾値での自己訓練
for i, threshold in enumerate(x_values):
self_training_clf = SelfTrainingClassifier(base_classifier, threshold=threshold)
skfolds = StratifiedKFold(n_splits=n_splits)
for fold, (train_index, test_index) in enumerate(skfolds.split(X, y)):
X_train = X[train_index]
y_train = y[train_index]
X_test = X[test_index]
y_test = y[test_index]
y_test_true = y_true[test_index]
self_training_clf.fit(X_train, y_train)
amount_labeled[i, fold] = (
total_samples
- np.unique(self_training_clf.labeled_iter_, return_counts=True)[1][0]
)
amount_iterations[i, fold] = np.max(self_training_clf.labeled_iter_)
y_pred = self_training_clf.predict(X_test)
scores[i, fold] = accuracy_score(y_test_true, y_pred)
基本的な分類器と scikit - learn の SelfTrainingClassifier クラスを使って、異なる閾値で自己訓練を行います。データを学習用とテスト用に分割するために層化 k 分割交差検証を使用します。その後、自己訓練分類器を学習セットに適合させ、テストセットでの分類器の精度を計算します。また、各分割についてのラベル付きサンプルの数と反復回数も保存します。
結果を可視化する
ax1 = plt.subplot(211)
ax1.errorbar(
x_values, scores.mean(axis=1), yerr=scores.std(axis=1), capsize=2, color="b"
)
ax1.set_ylabel("Accuracy", color="b")
ax1.tick_params("y", colors="b")
ax2 = ax1.twinx()
ax2.errorbar(
x_values,
amount_labeled.mean(axis=1),
yerr=amount_labeled.std(axis=1),
capsize=2,
color="g",
)
ax2.set_ylim(bottom=0)
ax2.set_ylabel("Amount of labeled samples", color="g")
ax2.tick_params("y", colors="g")
ax3 = plt.subplot(212, sharex=ax1)
ax3.errorbar(
x_values,
amount_iterations.mean(axis=1),
yerr=amount_iterations.std(axis=1),
capsize=2,
color="b",
)
ax3.set_ylim(bottom=0)
ax3.set_ylabel("Amount of iterations")
ax3.set_xlabel("Threshold")
plt.show()
Matplotlib を使って実験の結果をプロットします。上部のグラフは、適合終了時に分類器が利用できるラベル付きサンプルの数と、分類器の精度を示しています。下部のグラフは、サンプルがラベル付けされた最後の反復回数を示しています。
まとめ
この実験では、scikit - learn を使って異なる閾値で自己訓練を行う方法を学びました。最適な閾値は非常に低い閾値と非常に高い閾値の間にあり、適切な閾値を選ぶことで精度が大幅に向上することがわかりました。