Примечание
Перейти к концу для загрузки полного примера кода. Или запустить этот пример в браузере через 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.
Разделение данных
Здесь мы выбираем 5000 образцов для обучения и 10000 для тестирования. Чтобы действительно воспроизвести результаты в оригинальной статье о 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.55% Linear SVM score on 500 PolynomialCountSketch features: 76.92% Linear SVM score on 1000 PolynomialCountSketch features: 77.79% Linear SVM score on 2000 PolynomialCountSketch features: 78.59%
Установление модели 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()

Ссылки
[1] Pham, Ninh и Rasmus Pagh. «Быстрые и масштабируемые полиномиальные ядра с помощью явных отображений признаков». KDD ‘13 (2013). https://doi.org/10.1145/2487575.2487591
[2] Репозиторий наборов данных LIBSVM бинарного типа https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html
Общее время выполнения скрипта: (0 минут 32.661 секунды)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/kernel_approximation/plot_scalable_poly_kernels.html