Spec-Zone.ru › scikit-learn

Примечание

Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью 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()
Semi-supervised decision boundaries with varying fractions of labeled data, LabelSpreading with 10% labeled data, Self-training with 10% labeled data, LabelSpreading with 30% labeled data, Self-training with 30% labeled data, LabelSpreading with 100% labeled data, SVC with rbf kernel (equivalent to Self-training with 100% labeled data)

Мы видим, что границы принятия решений уже довольно близки к тем, которые получаются при использовании всех доступных размеченных обучающих данных, даже если взять лишь очень небольшую часть меток.

Интерпретация 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 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_semi_supervised_versus_svm_iris.ipynb

Download Python source code: plot_semi_supervised_versus_svm_iris.py

Download zipped: plot_semi_supervised_versus_svm_iris.zip

Связанные примеры

Классификация текстового набора данных с полуконтролируемым обучением

Влияние изменения порога на самообучение

Распространение меток для цифр: демонстрация производительности

Распространение меток для цифр: активное обучение

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API