Примечание
Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере через JupyterLite или Binder.
Масштабируемое обучение с аппроксимацией полиномиального ядра
В этом примере показано использование PolynomialCountSketch для эффективного построения аппроксимаций пространства признаков полиномиального ядра. Это используется для обучения линейных классификаторов, точность которых близка к точности классификаторов с ядром.
Мы используем набор данных Covtype [2], пытаясь воспроизвести эксперименты из оригинальной статьи о Tensor Sketch [1], то есть алгоритм, реализованный в PolynomialCountSketch.
Сначала мы вычисляем точность линейного классификатора на исходных признаках. Затем обучаем линейные классификаторы на разном количестве признаков (n_components), сгенерированных с помощью PolynomialCountSketch, и масштабируемым образом аппроксимируем точность классификатора с ядром.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Подготовка данных
Загрузим набор данных Covtype, который содержит 581 012 образцов с 54 признаками каждый, распределённых по 6 классам. Цель этого набора данных — предсказать тип лесного покрова только по картографическим переменным (без данных дистанционного зондирования). После загрузки мы преобразуем его в задачу бинарной классификации, чтобы привести к виду набора данных на веб-странице LIBSVM [2], который использовался в работе [1].
from sklearn.datasets import fetch_covtype X, y = fetch_covtype(return_X_y=True) y[y != 2] = 0 y[y == 2] = 1 # We will try to separate class 2 from the other 6 classes.
Разбиение данных
Здесь мы выбираем 5 000 образцов для обучения и 10 000 для тестирования. Чтобы в точности воспроизвести результаты оригинальной статьи о Tensor Sketch, выберите 100 000 образцов для обучения.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
X, y, train_size=5_000, test_size=10_000, random_state=42
)
Нормализация признаков
Теперь масштабируем признаки в диапазон [0, 1], чтобы привести их к формату набора данных на веб-странице LIBSVM, а затем нормализуем до единичной длины, как это сделано в оригинальной статье о Tensor Sketch [1].
from sklearn.pipeline import make_pipeline from sklearn.preprocessing import MinMaxScaler, Normalizer mm = make_pipeline(MinMaxScaler(), Normalizer()) X_train = mm.fit_transform(X_train) X_test = mm.transform(X_test)
Создание базовой модели
В качестве базовой модели обучим линейный SVM на исходных признаках и выведем точность. Мы также измерим и сохраним точность и время обучения, чтобы позже построить графики.
import time
from sklearn.svm import LinearSVC
results = {}
lsvm = LinearSVC()
start = time.time()
lsvm.fit(X_train, y_train)
lsvm_time = time.time() - start
lsvm_score = 100 * lsvm.score(X_test, y_test)
results["LSVM"] = {"time": lsvm_time, "score": lsvm_score}
print(f"Linear SVM score on raw features: {lsvm_score:.2f}%")
Linear SVM score on raw features: 75.62%
Создание модели с аппроксимацией ядра
Затем мы обучаем линейные SVM на признаках, сгенерированных с помощью PolynomialCountSketch при разных значениях n_components, демонстрируя, что такие аппроксимации признакового представления ядра повышают точность линейной классификации. В типичных прикладных сценариях n_components должно быть больше числа признаков во входном представлении, чтобы добиться улучшения по сравнению с линейной классификацией. Как правило, оптимальное соотношение оценки качества и затрат времени выполнения обычно достигается при n_components = 10 * n_features, хотя это может зависеть от конкретного набора данных. Обратите внимание: поскольку исходные образцы содержат 54 признака, явное отображение признаков полиномиального ядра четвёртой степени содержало бы приблизительно 8,5 миллиона признаков (точнее, 54^4). Благодаря PolynomialCountSketch мы можем сжать большую часть дискриминативной информации этого пространства признаков в гораздо более компактное представление. В этом примере мы проводим эксперимент всего один раз (n_runs = 1), однако на практике следует повторить эксперимент несколько раз, чтобы компенсировать стохастический характер PolynomialCountSketch.
from sklearn.kernel_approximation import PolynomialCountSketch
n_runs = 1
N_COMPONENTS = [250, 500, 1000, 2000]
for n_components in N_COMPONENTS:
ps_lsvm_time = 0
ps_lsvm_score = 0
for _ in range(n_runs):
pipeline = make_pipeline(
PolynomialCountSketch(n_components=n_components, degree=4),
LinearSVC(),
)
start = time.time()
pipeline.fit(X_train, y_train)
ps_lsvm_time += time.time() - start
ps_lsvm_score += 100 * pipeline.score(X_test, y_test)
ps_lsvm_time /= n_runs
ps_lsvm_score /= n_runs
results[f"LSVM + PS({n_components})"] = {
"time": ps_lsvm_time,
"score": ps_lsvm_score,
}
print(
f"Linear SVM score on {n_components} PolynomialCountSketch "
f"features: {ps_lsvm_score:.2f}%"
)
Linear SVM score on 250 PolynomialCountSketch features: 76.22% Linear SVM score on 500 PolynomialCountSketch features: 77.60% Linear SVM score on 1000 PolynomialCountSketch features: 77.75% Linear SVM score on 2000 PolynomialCountSketch features: 78.26%
Создание модели SVM с ядром
Обучим SVM с ядром, чтобы оценить, насколько хорошо PolynomialCountSketch аппроксимирует эффективность ядра. Разумеется, это может занять некоторое время, поскольку класс SVC обладает относительно низкой масштабируемостью. Именно поэтому аппроксиматоры ядер так полезны:
from sklearn.svm import SVC
ksvm = SVC(C=500.0, kernel="poly", degree=4, coef0=0, gamma=1.0)
start = time.time()
ksvm.fit(X_train, y_train)
ksvm_time = time.time() - start
ksvm_score = 100 * ksvm.score(X_test, y_test)
results["KSVM"] = {"time": ksvm_time, "score": ksvm_score}
print(f"Kernel-SVM score on raw features: {ksvm_score:.2f}%")
Kernel-SVM score on raw features: 79.78%
Сравнение результатов
Наконец, построим график результатов разных методов в зависимости от времени обучения. Как видно, SVM с ядром обеспечивает более высокую точность, однако время его обучения значительно больше и, что особенно важно, оно будет расти гораздо быстрее при увеличении числа обучающих образцов.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(7, 7))
ax.scatter(
[
results["LSVM"]["time"],
],
[
results["LSVM"]["score"],
],
label="Linear SVM",
c="green",
marker="^",
)
ax.scatter(
[
results["LSVM + PS(250)"]["time"],
],
[
results["LSVM + PS(250)"]["score"],
],
label="Linear SVM + PolynomialCountSketch",
c="blue",
)
for n_components in N_COMPONENTS:
ax.scatter(
[
results[f"LSVM + PS({n_components})"]["time"],
],
[
results[f"LSVM + PS({n_components})"]["score"],
],
c="blue",
)
ax.annotate(
f"n_comp.={n_components}",
(
results[f"LSVM + PS({n_components})"]["time"],
results[f"LSVM + PS({n_components})"]["score"],
),
xytext=(-30, 10),
textcoords="offset pixels",
)
ax.scatter(
[
results["KSVM"]["time"],
],
[
results["KSVM"]["score"],
],
label="Kernel SVM",
c="red",
marker="x",
)
ax.set_xlabel("Training time (s)")
ax.set_ylabel("Accuracy (%)")
ax.legend()
plt.show()

Литература
Общее время выполнения скрипта: (0 минут 20.253 секунды)
Связанные примеры
© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/kernel_approximation/plot_scalable_poly_kernels.html