Масштабирование признаков в машинном обучении

Beginner

This tutorial is from open-source community. Access the source code

Введение

Нормализация признаков - важный этап предварительной обработки для многих алгоритмов машинного обучения. Она включает в себя перемасштабирование каждого признака так, чтобы у него было стандартное отклонение 1 и среднее значение 0. В этом практическом занятии мы исследуем важность нормализации признаков и ее влияние на модели машинного обучения с использованием библиотеки scikit-learn в Python.

Советы по работе с ВМ

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

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook загрузится. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

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

Загрузка и подготовка данных

Мы загрузим датасет о винах из scikit-learn и разделим его на обучающую и тестовую выборки. Также мы масштабируем признаки в обучающей выборке с использованием StandardScaler из модуля предварительной обработки scikit-learn.

from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

X, y = load_wine(return_X_y=True, as_frame=True)
scaler = StandardScaler().set_output(transform="pandas")

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.30, random_state=42
)
scaled_X_train = scaler.fit_transform(X_train)

Влияние масштабирования на модель k-соседей

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

import matplotlib.pyplot as plt
from sklearn.inspection import DecisionBoundaryDisplay
from sklearn.neighbors import KNeighborsClassifier

X_plot = X[["proline", "hue"]]
X_plot_scaled = scaler.fit_transform(X_plot)
clf = KNeighborsClassifier(n_neighbors=20)

def fit_and_plot_model(X_plot, y, clf, ax):
    clf.fit(X_plot, y)
    disp = DecisionBoundaryDisplay.from_estimator(
        clf,
        X_plot,
        response_method="predict",
        alpha=0.5,
        ax=ax,
    )
    disp.ax_.scatter(X_plot["proline"], X_plot["hue"], c=y, s=20, edgecolor="k")
    disp.ax_.set_xlim((X_plot["proline"].min(), X_plot["proline"].max()))
    disp.ax_.set_ylim((X_plot["hue"].min(), X_plot["hue"].max()))
    return disp.ax_

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 6))

fit_and_plot_model(X_plot, y, clf, ax1)
ax1.set_title("KNN without scaling")

fit_and_plot_model(X_plot_scaled, y, clf, ax2)
ax2.set_xlabel("scaled proline")
ax2.set_ylabel("scaled hue")
_ = ax2.set_title("KNN with scaling")

Влияние масштабирования на уменьшение размерности при PCA

Мы будем использовать Анализ главных компонент (PCA), чтобы уменьшить размерность датасета о винах. Мы сравним главные компоненты, найденные с использованием PCA для не масштабированных данных, с теми, которые были получены, когда сначала масштабировали данные с использованием StandardScaler.

import pandas as pd
from sklearn.decomposition import PCA

pca = PCA(n_components=2).fit(X_train)
scaled_pca = PCA(n_components=2).fit(scaled_X_train)
X_train_transformed = pca.transform(X_train)
X_train_std_transformed = scaled_pca.transform(scaled_X_train)

first_pca_component = pd.DataFrame(
    pca.components_[0], index=X.columns, columns=["without scaling"]
)
first_pca_component["with scaling"] = scaled_pca.components_[0]
first_pca_component.plot.bar(
    title="Weights of the first principal component", figsize=(6, 8)
)

_ = plt.tight_layout()

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(10, 5))

target_classes = range(0, 3)
colors = ("blue", "red", "green")
markers = ("^", "s", "o")

for target_class, color, marker in zip(target_classes, colors, markers):
    ax1.scatter(
        x=X_train_transformed[y_train == target_class, 0],
        y=X_train_transformed[y_train == target_class, 1],
        color=color,
        label=f"class {target_class}",
        alpha=0.5,
        marker=marker,
    )

    ax2.scatter(
        x=X_train_std_transformed[y_train == target_class, 0],
        y=X_train_std_transformed[y_train == target_class, 1],
        color=color,
        label=f"class {target_class}",
        alpha=0.5,
        marker=marker,
    )

ax1.set_title("Unscaled training dataset after PCA")
ax2.set_title("Standardized training dataset after PCA")

for ax in (ax1, ax2):
    ax.set_xlabel("1st principal component")
    ax.set_ylabel("2nd principal component")
    ax.legend(loc="upper right")
    ax.grid()

_ = plt.tight_layout()

Влияние масштабирования на производительность модели

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

import numpy as np
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegressionCV
from sklearn.metrics import accuracy_score
from sklearn.metrics import log_loss

Cs = np.logspace(-5, 5, 20)

unscaled_clf = make_pipeline(pca, LogisticRegressionCV(Cs=Cs))
unscaled_clf.fit(X_train, y_train)

scaled_clf = make_pipeline(scaler, pca, LogisticRegressionCV(Cs=Cs))
scaled_clf.fit(X_train, y_train)

y_pred = unscaled_clf.predict(X_test)
y_pred_scaled = scaled_clf.predict(X_test)
y_proba = unscaled_clf.predict_proba(X_test)
y_proba_scaled = scaled_clf.predict_proba(X_test)

print("Test accuracy for the unscaled PCA")
print(f"{accuracy_score(y_test, y_pred):.2%}\n")
print("Test accuracy for the standardized data with PCA")
print(f"{accuracy_score(y_test, y_pred_scaled):.2%}\n")
print("Log-loss for the unscaled PCA")
print(f"{log_loss(y_test, y_proba):.3}\n")
print("Log-loss for the standardized data with PCA")
print(f"{log_loss(y_test, y_proba_scaled):.3}")

Резюме

В этом практическом занятии мы узнали о важности масштабирования признаков в машинном обучении и его влиянии на производительность модели. Мы исследовали влияние масштабирования признаков на модель k-ближайших соседей и на уменьшение размерности при помощи PCA. Также мы обучили модель логистической регрессии с данными, уменьшенными размерностью при помощи PCA, чтобы оценить влияние масштабирования признаков на производительность модели. Мы обнаружили, что масштабирование признаков перед уменьшением размерности приводит к компонентам одного порядка величины и улучшает разделимость классов, что влечет за собой лучшую производительность модели.