Spec-Zone.ru › scikit-learn

Примечание

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

Основные нововведения в scikit-learn 1.5

Мы рады объявить о выпуске scikit-learn 1.5! В него вошли многочисленные исправления ошибок и улучшения, а также несколько важных новых функций. Ниже мы подробно рассмотрим основные нововведения этого выпуска. Полный список всех изменений см. в примечаниях к выпуску.

Чтобы установить последнюю версию с помощью pip:

pip install --upgrade scikit-learn

или с помощью conda:

conda install -c conda-forge scikit-learn

FixedThresholdClassifier: настройка порога принятия решения бинарного классификатора

Все бинарные классификаторы scikit-learn используют фиксированный порог принятия решения 0.5 для преобразования оценок вероятности (то есть результатов predict_proba) в предсказания классов. Однако порог 0.5 почти никогда не подходит для конкретной задачи. FixedThresholdClassifier позволяет обернуть любой бинарный классификатор и задать пользовательский порог принятия решения.

from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import ConfusionMatrixDisplay
from sklearn.model_selection import train_test_split

X, y = make_classification(n_samples=10_000, weights=[0.9, 0.1], random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

classifier_05 = LogisticRegression(C=1e6, random_state=0).fit(X_train, y_train)
_ = ConfusionMatrixDisplay.from_estimator(classifier_05, X_test, y_test)
plot release highlights 1 5 0

Снижение порога, то есть возможность классифицировать больше объектов как принадлежащие к положительному классу, увеличивает число истинно положительных результатов ценой увеличения числа ложноположительных результатов (что хорошо известно из вогнутости ROC-кривой).

from sklearn.model_selection import FixedThresholdClassifier

classifier_01 = FixedThresholdClassifier(classifier_05, threshold=0.1)
classifier_01.fit(X_train, y_train)
_ = ConfusionMatrixDisplay.from_estimator(classifier_01, X_test, y_test)
plot release highlights 1 5 0

TunedThresholdClassifierCV: подбор порога принятия решения бинарного классификатора

Порог принятия решения бинарного классификатора можно подобрать для оптимизации заданной метрики с помощью TunedThresholdClassifierCV.

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

Рассмотрим произвольный пример, в котором:

  • каждый истинно положительный результат приносит 1 единицу прибыли, например евро, год жизни в добром здравии и т. д.;
  • истинно отрицательные результаты не приносят ни прибыли, ни убытка;
  • каждый ложноотрицательный результат обходится в 2 единицы;
  • каждый ложноположительный результат обходится в 0.1 единицы.

Наша метрика оценивает среднюю прибыль на один объект и определяется следующей функцией Python:

from sklearn.metrics import confusion_matrix


def custom_score(y_observed, y_pred):
    tn, fp, fn, tp = confusion_matrix(y_observed, y_pred, normalize="all").ravel()
    return tp - 2 * fn - 0.1 * fp


print("Untuned decision threshold: 0.5")
print(f"Custom score: {custom_score(y_test, classifier_05.predict(X_test)):.2f}")
Untuned decision threshold: 0.5
Custom score: -0.12

Интересно отметить, что средняя прибыль на одно предсказание отрицательна, то есть эта система принятия решений в среднем приносит убыток.

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

from sklearn.metrics import make_scorer
from sklearn.model_selection import TunedThresholdClassifierCV

custom_scorer = make_scorer(
    custom_score, response_method="predict", greater_is_better=True
)
tuned_classifier = TunedThresholdClassifierCV(
    classifier_05, cv=5, scoring=custom_scorer
).fit(X, y)

print(f"Tuned decision threshold: {tuned_classifier.best_threshold_:.3f}")
print(f"Custom score: {custom_score(y_test, tuned_classifier.predict(X_test)):.2f}")
Tuned decision threshold: 0.071
Custom score: 0.04

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

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

Для этого TunedThresholdClassifierCV использует поддержку маршрутизации метаданных (Руководство пользователя по маршрутизации метаданных), что позволяет оптимизировать сложные бизнес-метрики, как описано в примере Настройка порога принятия решения для обучения с учетом издержек.

Улучшение производительности PCA

В PCA появился новый решатель — "covariance_eigh". Для наборов данных с большим числом объектов и небольшим числом признаков он работает до десяти раз быстрее и требует меньше памяти, чем другие решатели.

from sklearn.datasets import make_low_rank_matrix
from sklearn.decomposition import PCA

X = make_low_rank_matrix(
    n_samples=10_000, n_features=100, tail_strength=0.1, random_state=0
)

pca = PCA(n_components=10, svd_solver="covariance_eigh").fit(X)
print(f"Explained variance: {pca.explained_variance_ratio_.sum():.2f}")
Explained variance: 0.88

Новый решатель также принимает разреженные входные данные:

from scipy.sparse import random

X = random(10_000, 100, format="csr", random_state=0)

pca = PCA(n_components=10, svd_solver="covariance_eigh").fit(X)
print(f"Explained variance: {pca.explained_variance_ratio_.sum():.2f}")
Explained variance: 0.13

Решатель "full" также был улучшен: теперь он использует меньше памяти и позволяет быстрее выполнять преобразование. Параметр svd_solver="auto" по умолчанию использует преимущества нового решателя и теперь может выбирать подходящий решатель для разреженных наборов данных.

Как и большинство других решателей PCA, новый решатель "covariance_eigh" может использовать вычисления на GPU, если входные данные переданы в виде массива PyTorch или CuPy и включена экспериментальная поддержка Array API.

К ColumnTransformer теперь можно обращаться по индексу

Теперь к преобразователям ColumnTransformer можно обращаться напрямую по имени с помощью индексирования.

import numpy as np

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler

X = np.array([[0, 1, 2], [3, 4, 5]])
column_transformer = ColumnTransformer(
    [("std_scaler", StandardScaler(), [0]), ("one_hot", OneHotEncoder(), [1, 2])]
)

column_transformer.fit(X)

print(column_transformer["std_scaler"])
print(column_transformer["one_hot"])
StandardScaler()
OneHotEncoder()

Пользовательские стратегии импутации для SimpleImputer

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

from sklearn.impute import SimpleImputer

X = np.array(
    [
        [-1.1, 1.1, 1.1],
        [3.9, -1.2, np.nan],
        [np.nan, 1.3, np.nan],
        [-0.1, -1.4, -1.4],
        [-4.9, 1.5, -1.5],
        [np.nan, 1.6, 1.6],
    ]
)


def smallest_abs(arr):
    """Return the smallest absolute value of a 1D array."""
    return np.min(np.abs(arr))


imputer = SimpleImputer(strategy=smallest_abs)

imputer.fit_transform(X)
array([[-1.1,  1.1,  1.1],
       [ 3.9, -1.2,  1.1],
       [ 0.1,  1.3,  1.1],
       [-0.1, -1.4, -1.4],
       [-4.9,  1.5, -1.5],
       [ 0.1,  1.6,  1.6]])

Попарные расстояния для нечисловых массивов

Теперь pairwise_distances может вычислять расстояния между нечисловыми массивами с помощью вызываемой метрики.

from sklearn.metrics import pairwise_distances

X = ["cat", "dog"]
Y = ["cat", "fox"]


def levenshtein_distance(x, y):
    """Return the Levenshtein distance between two strings."""
    if x == "" or y == "":
        return max(len(x), len(y))
    if x[0] == y[0]:
        return levenshtein_distance(x[1:], y[1:])
    return 1 + min(
        levenshtein_distance(x[1:], y),
        levenshtein_distance(x, y[1:]),
        levenshtein_distance(x[1:], y[1:]),
    )


pairwise_distances(X, Y, metric=levenshtein_distance)
array([[0., 3.],
       [3., 2.]])

Общее время выполнения скрипта: (0 минут 0.892 секунды)

Launch binder
Launch JupyterLite

Download Jupyter notebook: plot_release_highlights_1_5_0.ipynb

Download Python source code: plot_release_highlights_1_5_0.py

Download zipped: plot_release_highlights_1_5_0.zip

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

Постфактумная настройка порогового значения функции принятия решения

Настройка порога принятия решения для обучения с учетом издержек

Примеры использования FrozenEstimator

Основные нововведения в scikit-learn 1.6

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

Spec-Zone.ru

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