Примечание
Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.
Граница принятия решений полуконтролируемых классификаторов и SVM на наборе данных Iris
В этом примере сравниваются границы принятия решений, построенные двумя методами полуконтролируемого обучения, а именно LabelSpreading и SelfTrainingClassifier, при изменении доли размеченных обучающих данных от небольшой части до всего набора данных.
Оба метода используют ядра RBF: LabelSpreading применяет его по умолчанию, а SelfTrainingClassifier здесь сочетается с SVC в качестве базового оценивателя (в нём также по умолчанию используется ядро RBF), что позволяет провести корректное сравнение. При 100% размеченных данных SelfTrainingClassifier сводится к полностью контролируемому методу SVC, поскольку неразмеченных объектов, которым можно было бы назначить псевдометки, не остаётся.
Во втором разделе мы объясним, как вычисляется predict_proba в LabelSpreading и SelfTrainingClassifier.
Сравнение LabelSpreading и SelfTrainingClassifier по производительности см. в разделе Классификация текстового набора данных с полуконтролируемым обучением.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
from sklearn.calibration import CalibratedClassifierCV
from sklearn.datasets import load_iris
from sklearn.inspection import DecisionBoundaryDisplay
from sklearn.semi_supervised import LabelSpreading, SelfTrainingClassifier
from sklearn.svm import SVC
iris = load_iris()
X = iris.data[:, :2]
y = iris.target
rng = np.random.RandomState(42)
y_rand = rng.rand(y.shape[0])
y_10 = np.copy(y)
y_10[y_rand > 0.1] = -1 # set random samples to be unlabeled
y_30 = np.copy(y)
y_30[y_rand > 0.3] = -1
ls10 = (LabelSpreading().fit(X, y_10), y_10, "LabelSpreading with 10% labeled data")
ls30 = (LabelSpreading().fit(X, y_30), y_30, "LabelSpreading with 30% labeled data")
ls100 = (LabelSpreading().fit(X, y), y, "LabelSpreading with 100% labeled data")
base_classifier = CalibratedClassifierCV(SVC(gamma=0.5, random_state=42))
st10 = (
SelfTrainingClassifier(base_classifier).fit(X, y_10),
y_10,
"Self-training with 10% labeled data",
)
st30 = (
SelfTrainingClassifier(base_classifier).fit(X, y_30),
y_30,
"Self-training with 30% labeled data",
)
rbf_svc = (
base_classifier.fit(X, y),
y,
"SVC with rbf kernel\n(equivalent to Self-training with 100% labeled data)",
)
classifiers = (ls10, st10, ls30, st30, ls100, rbf_svc)
fig, axes = plt.subplots(nrows=3, ncols=2, sharex="col", sharey="row", figsize=(10, 12))
axes = axes.ravel()
for ax, (clf, y_train, title) in zip(axes, classifiers):
disp = DecisionBoundaryDisplay.from_estimator(
clf,
X,
response_method="predict_proba",
plot_method="contourf",
ax=ax,
)
colors = [
(1, 1, 1, 1) if label == -1 else disp.multiclass_colors_[label]
for label in y_train
]
ax.scatter(X[:, 0], X[:, 1], c=colors, edgecolor="black")
ax.set_title(title)
fig.suptitle(
"Semi-supervised decision boundaries with varying fractions of labeled data", y=1
)
handles = [
mpatches.Patch(
facecolor=color, edgecolor="black", label=iris.target_names[class_idx]
)
for class_idx, color in enumerate(disp.multiclass_colors_)
]
handles.append(mpatches.Patch(facecolor="white", edgecolor="black", label="Unlabeled"))
fig.legend(
handles=handles, loc="lower center", ncol=len(handles), bbox_to_anchor=(0.5, 0.0)
)
fig.tight_layout(rect=[0, 0.03, 1, 1])
plt.show()

Мы видим, что границы принятия решений уже довольно близки к тем, которые получаются при использовании всех доступных размеченных обучающих данных, даже если взять лишь очень небольшую часть меток.
Интерпретация predict_proba
predict_proba в LabelSpreading
LabelSpreading строит по данным граф сходства, по умолчанию используя ядро RBF. Это означает, что каждый объект соединён со всеми остальными весами, которые убывают с ростом квадрата евклидова расстояния между ними, масштабированного параметром gamma.
После построения взвешенного графа метки распространяются по его рёбрам. Каждый объект постепенно получает мягкое распределение меток, отражающее взвешенное среднее меток его соседей, пока процесс не сойдётся. Эти распределения для каждого объекта сохраняются в label_distributions_.
predict_proba вычисляет вероятности классов для новой точки, находя взвешенное среднее строк label_distributions_, где веса определяются сходством новой точки с обучающими объектами по ядру RBF. Затем значения среднего нормализуются повторно, чтобы их сумма равнялась единице.
Помните, что эти «вероятности» — оценки, основанные на графе, а не калиброванные апостериорные вероятности. Не следует придавать их абсолютным значениям чрезмерное значение.
from sklearn.metrics.pairwise import rbf_kernel
ls = ls100[0] # fitted LabelSpreading instance
x_query = np.array([[3.5, 1.5]]) # point in the soft blue region
# Step 1: similarities between query and all training samples
W = rbf_kernel(x_query, X, gamma=ls.gamma) # `gamma=20` by default
# Step 2: weighted average of label distributions
probs = np.dot(W, ls.label_distributions_)
# Step 3: normalize to sum to 1
probs /= probs.sum(axis=1, keepdims=True)
print("Manual:", probs)
print("API :", ls.predict_proba(x_query))
Manual: [[0.96 0.03 0.01]] API : [[0.96 0.03 0.01]]
predict_proba в SelfTrainingClassifier
SelfTrainingClassifier многократно обучает базовый оцениватель на текущих размеченных данных, а затем добавляет псевдометки для неразмеченных объектов, предсказанные вероятности которых превышают порог уверенности. Процесс продолжается, пока новые объекты можно размечать; после этого в атрибуте estimator_ хранится окончательно обученный базовый оцениватель.
При вызове predict_proba для SelfTrainingClassifier метод просто передаёт вызов этому окончательному оценивателю.
st = st10[0]
print("Manual:", st.estimator_.predict_proba(x_query))
print("API :", st.predict_proba(x_query))
Manual: [[0.41 0.37 0.22]] API : [[0.41 0.37 0.22]]
Оба метода позволяют рассматривать полуконтролируемое обучение как построение категориального распределения по классам для каждого объекта. LabelSpreading сохраняет эти распределения мягкими и обновляет их с помощью распространения по графу. Предсказания (включая predict_proba) по-прежнему зависят от обучающего набора, который необходимо хранить для вывода.
SelfTrainingClassifier использует эти распределения внутри алгоритма, чтобы во время обучения решать, каким неразмеченным объектам назначить псевдометки. Однако при предсказании возвращаемые вероятности поступают непосредственно от окончательно обученного оценивателя, поэтому для принятия решения не требуется хранить обучающие данные.
Общее время выполнения скрипта: (0 минут 1.685 секунды)
Связанные примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/semi_supervised/plot_semi_supervised_versus_svm_iris.html