在机器学习领域,自训练(Self-training)是一种半监督学习技术,它结合了有监督学习和无监督学习的特点。本文通过乳腺癌数据集来展示自训练分类器在不同阈值设置下的性能变化。在实验中,只保留了部分样本的标签,其余样本的标签被删除,以此来模拟半监督学习的环境。
实验中使用的是支持向量机(SVM)作为基础分类器,通过调整自训练分类器的阈值,观察其对分类准确度的影响。阈值的设定决定了分类器在自训练过程中对未标记样本的接受程度。较低的阈值意味着分类器会接受更多的未标记样本,而较高的阈值则意味着只有当分类器对样本的预测非常有信心时,才会将其添加到训练集中。
实验结果表明,在阈值较低时(例如0.4到0.5之间),分类器会从标记信心较低的样本中学习,这些样本很可能被错误标记,导致分类器的准确度下降。在这种情况下,分类器几乎标记了所有样本,并且仅在一次迭代中完成。而在阈值非常高的情况下(例如0.9到1之间),分类器不会增加其数据集,因此通过0.9999的阈值得到的准确度与普通有监督分类器相同。
最佳准确度出现在这两个极端之间的阈值,大约在0.7左右。为了验证这一点,进行了交叉验证,使用了3折的方法来评估不同阈值下的分类器性能。通过绘制图表,可以直观地看到不同阈值下分类器的准确度和标记样本数量的变化。
以下是实验中使用的Python代码,它展示了如何使用scikit-learn库中的SelfTrainingClassifier类来实现自训练分类器,并根据不同的阈值进行训练和评估。
import matplotlib.pyplot as plt
import numpy as np
from sklearn import datasets
from sklearn.metrics import accuracy_score
from sklearn.model_selection import StratifiedKFold
from sklearn.semi_supervised import SelfTrainingClassifier
from sklearn.svm import SVC
from sklearn.utils import shuffle
n_splits = 3
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]
base_classifier = SVC(probability=True, gamma=0.001, random_state=42)
x_values = np.arange(0.4, 1.05, 0.05)
x_values = np.append(x_values, 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)
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()
通过上述代码,可以看到自训练分类器在不同阈值下的表现。实验结果表明,选择合适的阈值对于提高分类器的性能至关重要。在实际应用中,可以通过调整阈值来平衡分类器的泛化能力和对未标记样本的利用程度。
此外,实验还提供了一些额外的资源,包括Jupyter笔记本和Python源代码,供有兴趣的读者进一步探索和学习。通过这些资源,读者可以更深入地理解自训练分类器的工作原理和实现细节。