Spec-Zone.ru › scikit-learn

Примечание

Перейти в конец, чтобы скачать полный код примера или запустить этот пример в браузере с помощью JupyterLite или Binder.

Пример конвейера для извлечения признаков из текста и оценки

В этом примере используется набор данных Текстовый набор данных 20 newsgroups, который будет автоматически загружен, сохранён в кэше и повторно использован для примера классификации документов.

В этом примере мы настраиваем гиперпараметры определённого классификатора с помощью 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
Pipeline(steps=[('vect', TfidfVectorizer()), ('clf', ComplementNB())])
В среде Jupyter повторно выполните эту ячейку, чтобы отобразить представление HTML, или доверьте этому блокноту.
На GitHub невозможно отобразить представление HTML; попробуйте открыть эту страницу на nbviewer.org.
Параметры
steps steps: список кортежей

Список кортежей (название шага, оцениватель), которые необходимо объединить
в последовательном порядке. Для совместимости с API scikit-learn все шаги
должны определять `fit`. Все шаги, кроме последнего, должны также определять `transform`. Подробнее см.
:ref:`Объединение оценивателей <combining_estimators>`.
[('vect', ...), ('clf', ...)]
transform_input transform_input: список строк, по умолчанию None

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

Это позволяет преобразовывать некоторые входные аргументы ``fit`` (кроме ``X``)
с помощью шагов конвейера вплоть до шага, которому они
необходимы. Требование задаётся с помощью :ref:`маршрутизации метаданных <metadata_routing>`.
Например, это можно использовать для передачи проверочной выборки через конвейер.

Этот параметр можно задать только при включённой маршрутизации метаданных, которую
можно включить с помощью ``sklearn.set_config(enable_metadata_routing=True)``.

.. versionadded:: 1.6
None
memory memory: строка или объект с интерфейсом joblib.Memory, по умолчанию None

Используется для кэширования обученных преобразователей конвейера. Последний шаг
никогда не кэшируется, даже если он является преобразователем. По умолчанию
кэширование не выполняется. Если задана строка, она обозначает путь к
каталогу кэша. Включение кэширования приводит к клонированию преобразователей
перед обучением. Поэтому экземпляр преобразователя, переданный
конвейеру, нельзя проверить напрямую. Используйте атрибут ``named_steps``
или ``steps``, чтобы проверить оцениватели в конвейере. Кэширование
преобразователей полезно, когда обучение занимает много времени. Пример включения кэширования см.
в :ref:`sphx_glr_auto_examples_neighbors_plot_caching_nearest_neighbors.py`.
None
verbose verbose: bool, по умолчанию False

Если значение True, по завершении каждого шага будет выводиться затраченное на него
время.
False
Параметры
input input: {'filename', 'file', 'content'}, default='content'

- Если `'filename'`, предполагается, что последовательность, переданная
в качестве аргумента fit, представляет собой список имён файлов, которые необходимо прочитать, чтобы получить
исходное содержимое для анализа.

- Если `'file'`, элементы последовательности должны иметь метод 'read' (файлоподобный
объект), который вызывается для получения байтов в памяти.

- Если `'content'`, ожидается, что входные данные представляют собой последовательность элементов,
которые могут иметь тип string или byte.
'content'
encoding encoding: str, default='utf-8'

Если для анализа переданы байты или файлы, эта кодировка используется для
декодирования.
'utf-8'
decode_error decode_error: {'strict', 'ignore', 'replace'}, default='strict'

Инструкция о том, что делать, если для анализа передана последовательность байтов,
содержащая символы, не входящие в указанную `encoding`. По умолчанию используется
'strict', то есть будет вызвано исключение UnicodeDecodeError. Другие
значения: 'ignore' и 'replace'.
'strict'
strip_accents strip_accents: {'ascii', 'unicode'} или callable, default=None

Удалять диакритические знаки и выполнять другую нормализацию символов
на этапе предварительной обработки.
'ascii' — быстрый метод, работающий только с символами, для которых существует
прямое соответствие в ASCII.
'unicode' — немного более медленный метод, работающий с любыми символами.
None (по умолчанию) означает, что нормализация символов не выполняется.

И 'ascii', и 'unicode' используют нормализацию NFKD из
:func:`unicodedata.normalize`.
None
lowercase lowercase: bool, default=True

Перед токенизацией преобразовывать все символы в нижний регистр.
True
preprocessor preprocessor: callable, default=None

Заменяет этап предварительной обработки (преобразования строк),
сохраняя этапы токенизации и генерации n-грамм.
Применяется, только если ``analyzer`` не является callable.
None
tokenizer tokenizer: callable, default=None

Заменяет этап токенизации строк, сохраняя этапы
предварительной обработки и генерации n-грамм.
Применяется, только если ``analyzer == 'word'``.
None
analyzer analyzer: {'word', 'char', 'char_wb'} или callable, default='word'

Определяет, должны ли признаки состоять из словесных или символьных n-грамм.
Вариант 'char_wb' создаёт символьные n-граммы только из текста внутри
границ слов; n-граммы на краях слов дополняются пробелом.

Если передан callable, он используется для извлечения последовательности признаков
из исходных необработанных входных данных.

.. versionchanged:: 0.21
Начиная с версии 0.21, если ``input`` имеет значение ``'filename'`` или ``'file'``, данные
сначала считываются из файла, а затем передаются указанному callable
analyzer.
'word'
stop_words stop_words: {'english'}, list, default=None

Если задана строка, она передаётся в _check_stop_list, который возвращает соответствующий список
стоп-слов. В настоящее время поддерживается только строковое
значение 'english'.
С 'english' связано несколько известных проблем, поэтому следует
рассмотреть альтернативный вариант (см. :ref:`stop_words`).

Если задан список, он считается списком стоп-слов, и все слова из него
будут удалены из результирующих токенов.
Применяется, только если ``analyzer == 'word'``.

Если задано None, стоп-слова не используются. В этом случае установка `max_df`
в более высокое значение, например в диапазоне (0.7, 1.0), позволяет автоматически обнаруживать
и отфильтровывать стоп-слова на основе частоты терминов в документах корпуса.
None
token_pattern token_pattern: str, default=r"(?u)\\b\\w\\w+\\b"

Регулярное выражение, задающее, что считается «токеном»; используется только
если ``analyzer == 'word'``. Регулярное выражение по умолчанию выбирает токены из 2
или более буквенно-цифровых символов (пунктуация полностью игнорируется
и всегда рассматривается как разделитель токенов).

Если в token_pattern есть захватывающая группа, токеном становится
содержимое захваченной группы, а не всё совпадение.
Допускается не более одной захватывающей группы.
'(?u)\\b\\w\\w+\\b'
ngram_range ngram_range: tuple (min_n, max_n), default=(1, 1)

Нижняя и верхняя границы диапазона значений n для извлекаемых
n-грамм. Используются все значения n, удовлетворяющие условию min_n <= n <= max_n.
Например, ``ngram_range`` со значением ``(1, 1)`` означает, что будут использоваться только
униграммы, ``(1, 2)`` — униграммы и биграммы, а ``(2, 2)`` —
только биграммы.
Применяется, только если ``analyzer`` не является callable.
(1, ...)
max_df max_df: float или int, default=1.0

При создании словаря игнорировать термины, частота встречаемости которых в документах
строго превышает заданный порог (стоп-слова, специфичные для корпуса).
Если задано число с плавающей точкой в диапазоне [0.0, 1.0], параметр обозначает долю
документов; целое число задаёт абсолютное количество.
Этот параметр игнорируется, если vocabulary не равен None.
1.0
min_df min_df: float или int, default=1

При создании словаря игнорировать термины, частота встречаемости которых в документах
строго ниже заданного порога. В литературе это значение также
называют порогом отсечения.
Если задано число с плавающей точкой в диапазоне [0.0, 1.0], параметр обозначает долю
документов; целое число задаёт абсолютное количество.
Этот параметр игнорируется, если vocabulary не равен None.
1
max_features max_features: int, default=None

Если задано значение, отличное от None, строится словарь, содержащий только верхние
`max_features` терминов, упорядоченных по частоте встречаемости во всём корпусе.
В противном случае используются все признаки.

Этот параметр игнорируется, если vocabulary не равен None.
None
vocabulary vocabulary: Mapping или iterable, default=None

Либо Mapping (например, dict), где ключи — термины, а значения —
индексы в матрице признаков, либо iterable по терминам. Если значение
не задано, словарь определяется по входным документам.
None
binary binary: bool, default=False

Если True, все ненулевые значения количества терминов заменяются на 1. Это не означает,
что выходные данные будут содержать только значения 0/1; это означает лишь, что член tf в tf-idf
является бинарным. (Установите `binary` в True, `use_idf` в False и
`norm` в None, чтобы получить выходные данные со значениями 0/1).
False
dtype dtype: dtype, default=float64

Тип матрицы, возвращаемой методами fit_transform() или transform().
<class 'numpy.float64'>
norm norm: {'l1', 'l2'} или None, default='l2'

Каждая выходная строка будет иметь единичную норму:

- 'l2': Сумма квадратов элементов вектора равна 1. Косинусное
сходство двух векторов равно их скалярному произведению, если была применена норма l2.
- 'l1': Сумма абсолютных значений элементов вектора равна 1.
См. :func:`~sklearn.preprocessing.normalize`.
- None: нормализация не выполняется.
'l2'
use_idf use_idf: bool, default=True

Включить взвешивание с использованием обратной частоты документов. Если False, idf(t) = 1.
True
smooth_idf smooth_idf: bool, default=True

Сглаживать веса idf, прибавляя единицу к частоте документов, как если бы был найден
дополнительный документ, содержащий каждый термин коллекции
ровно один раз. Предотвращает деление на ноль.
True
sublinear_tf sublinear_tf: bool, по умолчанию=False

Применять суб-линейное масштабирование tf, то есть заменять tf на 1 + log(tf).
False
Параметры
alpha alpha: float or array-like of shape (n_features,), по умолчанию=1.0

Параметр аддитивного сглаживания (Лапласа/Лидстоуна)
(задайте alpha=0 и force_alpha=True, чтобы отключить сглаживание).
1.0
force_alpha force_alpha: bool, по умолчанию=True

Если False и alpha меньше 1e-10, значение alpha будет установлено равным
1e-10. Если True, значение alpha останется без изменений. Это может привести к
численным ошибкам, если alpha слишком близко к 0.

.. добавлено в версии:: 1.2
.. изменено в версии:: 1.4
Значение `force_alpha` по умолчанию изменено на `True`.
True
fit_prior fit_prior: bool, по умолчанию=True

Используется только в особом случае, когда в обучающем наборе имеется один класс.
True
class_prior class_prior: array-like of shape (n_classes,), по умолчанию=None

Апостериорные вероятности классов. Не используется.
None
norm norm: bool, по умолчанию=False

Выполняется ли дополнительная нормализация весов. Поведение
по умолчанию соответствует реализациям в Mahout и Weka,
которые не следуют полностью алгоритму, описанному в таблице 9
статьи.
False


Мы задаём сетку гиперпараметров, которую должен исследовать 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 33.493s
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. Это помогает находить взаимосвязи между более чем двумя гиперпараметрами и лучше понимать их значимость для повышения эффективности конвейера.

Для оси alpha мы применяем преобразование math.log10, чтобы расширить активный диапазон и сделать график нагляднее. Значение \(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 минут 36.426 секунд)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_grid_search_text_feature_extraction.ipynb

Download Python source code: plot_grid_search_text_feature_extraction.py

Download zipped: plot_grid_search_text_feature_extraction.zip

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

Классификация текстовых документов с использованием разреженных признаков

Сравнение моделей случайного леса и гистограммного градиентного бустинга

Анализ сходимости моделей логистической регрессии со штрафом

Преобразователь столбцов для данных смешанных типов

© 2007–2026 The scikit-learn developers
Licensed under the 3-clause BSD License.
https://scikit-learn.org/1.9/auto_examples/model_selection/plot_grid_search_text_feature_extraction.html

Spec-Zone.ru

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