Примечание
Перейти к концу для загрузки полного примера кода. или для запуска этого примера в вашем браузере через JupyterLite или Binder
Пример конвейера для извлечения и оценки признаков текста
Набор данных, используемый в этом примере, — это набор данных 20 новостных групп, который будет автоматически загружен, кэширован и повторно использован для примера классификации документов.
В этом примере мы настраиваем гиперпараметры определенного классификатора с помощью RandomizedSearchCV. Для демонстрации производительности других классификаторов см. блокнот Классификация текстовых документов с использованием разреженных признаков.
# Authors: The scikit-learn developers # SPDX-License-Identifier: BSD-3-Clause
Загрузка данных
Мы загружаем две категории из обучающего набора данных. Вы можете изменить количество категорий, добавив их названия в список или установив categories=None при вызове загрузчика набора данных fetch_20newsgroups, чтобы получить все 20.
from sklearn.datasets import fetch_20newsgroups
categories = [
"alt.atheism",
"talk.religion.misc",
]
data_train = fetch_20newsgroups(
subset="train",
categories=categories,
shuffle=True,
random_state=42,
remove=("headers", "footers", "quotes"),
)
data_test = fetch_20newsgroups(
subset="test",
categories=categories,
shuffle=True,
random_state=42,
remove=("headers", "footers", "quotes"),
)
print(f"Loading 20 newsgroups dataset for {len(data_train.target_names)} categories:")
print(data_train.target_names)
print(f"{len(data_train.data)} documents")
Loading 20 newsgroups dataset for 2 categories: ['alt.atheism', 'talk.religion.misc'] 857 documents
Конвейер с настройкой гиперпараметров
Мы определяем конвейер, объединяющий векторизатор признаков текста с простым, но эффективным классификатором для классификации текста.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import ComplementNB
from sklearn.pipeline import Pipeline
pipeline = Pipeline(
[
("vect", TfidfVectorizer()),
("clf", ComplementNB()),
]
)
pipeline
Мы определяем набор гиперпараметров, которые будут исследоваться с помощью RandomizedSearchCV. Использование GridSearchCV вместо этого исследует все возможные комбинации на сетке, что может быть дорогостоящим по вычислительной сложности, тогда как параметр n_iter из RandomizedSearchCV контролирует количество различных случайных комбинаций, которые оцениваются. Обратите внимание, что установка n_iter больше, чем количество возможных комбинаций на сетке, приведет к повторному изучению уже исследованных комбинаций. Мы ищем лучшую комбинацию параметров как для извлечения признаков (vect__), так и для классификатора (clf__).
import numpy as np
parameter_grid = {
"vect__max_df": (0.2, 0.4, 0.6, 0.8, 1.0),
"vect__min_df": (1, 3, 5, 10),
"vect__ngram_range": ((1, 1), (1, 2)), # unigrams or bigrams
"vect__norm": ("l1", "l2"),
"clf__alpha": np.logspace(-6, 6, 13),
}
В этом случае n_iter=40 не является исчерпывающим поиском сетки гиперпараметров. На практике было бы интересно увеличить параметр n_iter, чтобы получить более информативный анализ. Вследствие этого увеличивается время вычислений. Мы можем уменьшить его, используя параллелизацию при оценке комбинаций параметров, увеличив количество используемых процессоров с помощью параметра n_jobs.
from pprint import pprint
from sklearn.model_selection import RandomizedSearchCV
random_search = RandomizedSearchCV(
estimator=pipeline,
param_distributions=parameter_grid,
n_iter=40,
random_state=0,
n_jobs=2,
verbose=1,
)
print("Performing grid search...")
print("Hyperparameters to be evaluated:")
pprint(parameter_grid)
Performing grid search...
Hyperparameters to be evaluated:
{'clf__alpha': array([1.e-06, 1.e-05, 1.e-04, 1.e-03, 1.e-02, 1.e-01, 1.e+00, 1.e+01,
1.e+02, 1.e+03, 1.e+04, 1.e+05, 1.e+06]),
'vect__max_df': (0.2, 0.4, 0.6, 0.8, 1.0),
'vect__min_df': (1, 3, 5, 10),
'vect__ngram_range': ((1, 1), (1, 2)),
'vect__norm': ('l1', 'l2')}
from time import time
t0 = time()
random_search.fit(data_train.data, data_train.target)
print(f"Done in {time() - t0:.3f}s")
Fitting 5 folds for each of 40 candidates, totalling 200 fits Done in 35.713s
print("Best parameters combination found:")
best_parameters = random_search.best_estimator_.get_params()
for param_name in sorted(parameter_grid.keys()):
print(f"{param_name}: {best_parameters[param_name]}")
Best parameters combination found: clf__alpha: 0.01 vect__max_df: 0.2 vect__min_df: 1 vect__ngram_range: (1, 1) vect__norm: l1
test_accuracy = random_search.score(data_test.data, data_test.target)
print(
"Accuracy of the best parameters using the inner CV of "
f"the random search: {random_search.best_score_:.3f}"
)
print(f"Accuracy on test set: {test_accuracy:.3f}")
Accuracy of the best parameters using the inner CV of the random search: 0.816 Accuracy on test set: 0.709
Префиксы vect и clf необходимы, чтобы избежать возможных неоднозначностей в конвейере, но не являются необходимыми для визуализации результатов. По этой причине мы определяем функцию, которая переименует настроенные гиперпараметры и улучшит читаемость.
import pandas as pd
def shorten_param(param_name):
"""Remove components' prefixes in param_name."""
if "__" in param_name:
return param_name.rsplit("__", 1)[1]
return param_name
cv_results = pd.DataFrame(random_search.cv_results_)
cv_results = cv_results.rename(shorten_param, axis=1)
Мы можем использовать plotly.express.scatter для визуализации компромисса между временем оценки и средним тестовым результатом (т.е. «CV-оценкой»). Наведение курсора на точку отображает соответствующие параметры. Полосы ошибок соответствуют одному стандартному отклонению, рассчитанному в различных итерациях перекрестной проверки.
import plotly.express as px
param_names = [shorten_param(name) for name in parameter_grid.keys()]
labels = {
"mean_score_time": "CV Score time (s)",
"mean_test_score": "CV score (accuracy)",
}
fig = px.scatter(
cv_results,
x="mean_score_time",
y="mean_test_score",
error_x="std_score_time",
error_y="std_test_score",
hover_data=param_names,
labels=labels,
)
fig.update_layout(
title={
"text": "trade-off between scoring time and mean test score",
"y": 0.95,
"x": 0.5,
"xanchor": "center",
"yanchor": "top",
}
)
fig
Обратите внимание, что кластер моделей в верхнем левом углу графика имеет наилучший баланс между точностью и временем оценки. В данном случае использование биграм увеличивает требуемое время оценки без существенного улучшения точности конвейера.
Примечание
Дополнительную информацию о том, как настроить автоматическую настройку для максимального повышения показателя и минимизации времени оценки, см. в блокноте-примере Настройка стратегии переподгонки при поиске сетки с перекрестной проверкой.
Мы также можем использовать plotly.express.parallel_coordinates для дополнительной визуализации средней тестовой оценки как функции настроенных гиперпараметров. Это помогает найти взаимодействия между более чем двумя гиперпараметрами и дает представление об их важности для улучшения производительности конвейера.
Мы применяем преобразование math.log10 к оси alpha, чтобы расширить активный диапазон и улучшить читаемость графика. Значение \(x\) на этой оси следует понимать как \(10^x\).
import math
column_results = param_names + ["mean_test_score", "mean_score_time"]
transform_funcs = dict.fromkeys(column_results, lambda x: x)
# Using a logarithmic scale for alpha
transform_funcs["alpha"] = math.log10
# L1 norms are mapped to index 1, and L2 norms to index 2
transform_funcs["norm"] = lambda x: 2 if x == "l2" else 1
# Unigrams are mapped to index 1 and bigrams to index 2
transform_funcs["ngram_range"] = lambda x: x[1]
fig = px.parallel_coordinates(
cv_results[column_results].apply(transform_funcs),
color="mean_test_score",
color_continuous_scale=px.colors.sequential.Viridis_r,
labels=labels,
)
fig.update_layout(
title={
"text": "Parallel coordinates plot of text classifier pipeline",
"y": 0.99,
"x": 0.5,
"xanchor": "center",
"yanchor": "top",
}
)
fig
На графике параллельных координат значения гиперпараметров отображаются на разных столбцах, а метрика производительности кодируется цветом. Вы можете выбрать диапазон результатов, нажав и удерживая на любой оси графика параллельных координат. Затем вы можете перемещать выбор диапазона и перекрещивать два выбора, чтобы увидеть пересечения. Вы можете отменить выбор, снова нажав на ту же ось.
В частности, для данного поиска гиперпараметров интересно отметить, что лучшие модели, по-видимому, не зависят от регуляризации norm, но зависят от баланса между max_df, min_df и силой регуляризации alpha. Причина в том, что включение шумных признаков (т.е. max_df близких к \(1.0\) или min_df близких к \(0\)) приводит к переобучению и поэтому требует большей регуляризации для компенсации. Меньшее количество признаков требует меньшей регуляризации и меньшего времени оценки.
Лучшие результаты точности достигаются, когда alpha находится между \(10^{-6}\) и \(10^0\), независимо от гиперпараметра norm.
Общее время выполнения скрипта: (0 минут 37.954 секунды)
Связанные примеры
© 2007–2025 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.6/auto_examples/model_selection/plot_grid_search_text_feature_extraction.html