Перейти к содержанию

Шпаргалка: sklearn

~4 минуты чтения

Предварительно: Выбор модели | Метрики

Sklearn -- главная библиотека для классического ML в Python. Единый API: fit() / predict() / transform() для всех алгоритмов. Pipeline автоматически предотвращает data leakage. Эта шпаргалка -- рабочий reference с копируемым кодом для каждого этапа: preprocessing -> model selection -> evaluation.

Быстрый старт

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score

# Базовый пайплайн
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # (1)!
X_test_scaled = scaler.transform(X_test)  # (2)!

model.fit(X_train_scaled, y_train)
y_pred = model.predict(X_test_scaled)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
  1. fit_transform = fit + transform за один вызов. Scaler запоминает mean/std с train данных.
  2. Только transform на тесте! fit_transform на тесте = data leakage (scaler увидит тестовые статистики).

Classification

Алгоритм Когда использовать Ключевые параметры Код
LogisticRegression Линейно разделимые классы, baseline C, penalty, solver LogisticRegression(C=1.0)
RandomForestClassifier Универсальный, feature importance n_estimators, max_depth, min_samples_split RandomForestClassifier(n_estimators=100)
GradientBoostingClassifier Высокое качество, медленный n_estimators, learning_rate, max_depth GradientBoostingClassifier(n_estimators=100)
SVC Нелинейные границы, малые данные C, kernel, gamma SVC(kernel='rbf', C=1.0)
KNeighborsClassifier Простой baseline, малые данные n_neighbors, weights, metric KNeighborsClassifier(n_neighbors=5)
DecisionTreeClassifier Интерпретируемость max_depth, min_samples_split DecisionTreeClassifier(max_depth=5)
GaussianNB Текст, быстрый baseline var_smoothing GaussianNB()
MLPClassifier Нелинейные зависимости hidden_layer_sizes, alpha, learning_rate MLPClassifier(hidden_layer_sizes=(100,))

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

from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.neural_network import MLPClassifier

# Logistic Regression с регуляризацией
lr = LogisticRegression(
    C=0.1,              # Сила регуляризации (меньше = сильнее)
    penalty='l2',       # l1, l2, elasticnet, None
    solver='lbfgs',     # lbfgs, liblinear, saga
    max_iter=1000,
    class_weight='balanced'  # Для дисбаланса классов
)

# Random Forest
rf = RandomForestClassifier(
    n_estimators=100,       # Количество деревьев
    max_depth=10,           # Глубина деревьев
    min_samples_split=5,    # Мин. примеров для разбиения
    min_samples_leaf=2,     # Мин. примеров в листе
    max_features='sqrt',    # Признаков на разбиение
    n_jobs=-1,              # Все ядра CPU
    random_state=42
)

# SVM с RBF kernel
svm = SVC(
    C=1.0,              # Штраф за ошибки
    kernel='rbf',       # linear, poly, rbf, sigmoid
    gamma='scale',      # Ширина ядра
    probability=True    # Для predict_proba
)

Regression

Алгоритм Когда использовать Ключевые параметры Код
LinearRegression Baseline, интерпретируемость - LinearRegression()
Ridge Много признаков, мультиколлинеарность alpha Ridge(alpha=1.0)
Lasso Feature selection, sparse alpha Lasso(alpha=1.0)
ElasticNet Комбинация Ridge + Lasso alpha, l1_ratio ElasticNet(alpha=1.0, l1_ratio=0.5)
RandomForestRegressor Нелинейные зависимости n_estimators, max_depth RandomForestRegressor(n_estimators=100)
GradientBoostingRegressor Высокое качество n_estimators, learning_rate GradientBoostingRegressor()
SVR Нелинейные, малые данные C, kernel, epsilon SVR(kernel='rbf')
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor

# Ridge Regression
ridge = Ridge(
    alpha=1.0,          # Сила L2 регуляризации
    fit_intercept=True
)

# Lasso (создаёт sparse модель)
lasso = Lasso(
    alpha=0.1,          # Сила L1 регуляризации
    max_iter=10000
)

# ElasticNet
elastic = ElasticNet(
    alpha=1.0,          # Общая сила регуляризации
    l1_ratio=0.5        # Баланс L1/L2 (0=Ridge, 1=Lasso)
)

Clustering

Алгоритм Когда использовать Ключевые параметры Код
KMeans Сферические кластеры n_clusters, init, n_init KMeans(n_clusters=3)
DBSCAN Произвольная форма, выбросы eps, min_samples DBSCAN(eps=0.5, min_samples=5)
AgglomerativeClustering Иерархия кластеров n_clusters, linkage AgglomerativeClustering(n_clusters=3)
GaussianMixture Мягкая кластеризация n_components, covariance_type GaussianMixture(n_components=3)
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.mixture import GaussianMixture

# K-Means
kmeans = KMeans(
    n_clusters=3,
    init='k-means++',   # Умная инициализация
    n_init=10,          # Количество запусков
    max_iter=300,
    random_state=42
)
labels = kmeans.fit_predict(X)
centers = kmeans.cluster_centers_

# DBSCAN (не нужно задавать k)
dbscan = DBSCAN(
    eps=0.5,            # Радиус окрестности
    min_samples=5,      # Мин. точек для core point
    metric='euclidean'
)
labels = dbscan.fit_predict(X)  # -1 = выброс

Preprocessing

Scaling

from sklearn.preprocessing import (
    StandardScaler,     # z-score: (x - mean) / std
    MinMaxScaler,       # [0, 1]: (x - min) / (max - min)
    RobustScaler,       # Устойчив к выбросам: (x - median) / IQR
    MaxAbsScaler,       # [-1, 1] для sparse данных
    Normalizer          # L2 норма для каждого примера
)

# Стандартизация (для большинства алгоритмов)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # fit + transform на train
X_test_scaled = scaler.transform(X_test)        # ТОЛЬКО transform на test!

# Нормализация [0, 1]
minmax = MinMaxScaler(feature_range=(0, 1))

# Для выбросов
robust = RobustScaler(quantile_range=(25, 75))

fit_transform на тестовых данных = data leakage

scaler.fit_transform(X_test) -- грубая ошибка. fit считает mean/std по данным. Если сделать fit на тесте -- scaler узнает распределение тестовых данных, и метрики будут завышены. Правильно: fit_transform ТОЛЬКО на train, потом transform на test/val/prod. Pipeline автоматически делает это правильно -- используйте Pipeline для любого preprocessing.

Encoding

from sklearn.preprocessing import (
    LabelEncoder,       # Категории -> числа
    OneHotEncoder,      # Категории -> бинарные столбцы
    OrdinalEncoder      # Порядковые категории -> числа
)

# Label Encoding (для target)
le = LabelEncoder()
y_encoded = le.fit_transform(y)
y_decoded = le.inverse_transform(y_encoded)

# One-Hot Encoding
ohe = OneHotEncoder(
    sparse_output=False,    # Dense matrix
    drop='first',           # Избежать dummy trap
    handle_unknown='ignore' # Для новых категорий
)
X_encoded = ohe.fit_transform(X[['category_column']])

Imputation

from sklearn.impute import SimpleImputer, KNNImputer

# Простая импутация
imputer = SimpleImputer(
    strategy='mean'     # mean, median, most_frequent, constant
)
X_imputed = imputer.fit_transform(X)

# KNN импутация (лучше качество)
knn_imputer = KNNImputer(n_neighbors=5)
X_imputed = knn_imputer.fit_transform(X)

Feature Selection

from sklearn.feature_selection import (
    SelectKBest,
    SelectFromModel,
    RFE,
    f_classif, f_regression, chi2, mutual_info_classif
)

# По статистическому тесту
selector = SelectKBest(score_func=f_classif, k=10)
X_selected = selector.fit_transform(X, y)
selected_features = X.columns[selector.get_support()]

# По важности модели
from sklearn.ensemble import RandomForestClassifier
selector = SelectFromModel(
    RandomForestClassifier(n_estimators=100),
    threshold='median'
)
X_selected = selector.fit_transform(X, y)

# Recursive Feature Elimination
rfe = RFE(
    estimator=RandomForestClassifier(),
    n_features_to_select=10,
    step=1
)
X_selected = rfe.fit_transform(X, y)
rankings = rfe.ranking_  # 1 = selected

Model Selection

Train-Test Split

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y,
    test_size=0.2,          # 20% на тест
    random_state=42,        # Воспроизводимость
    stratify=y              # Сохранить пропорции классов
)

Cross-Validation

from sklearn.model_selection import (
    cross_val_score,
    cross_validate,
    KFold,
    StratifiedKFold,
    TimeSeriesSplit
)

# Простая кросс-валидация
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')
print(f"Mean: {scores.mean():.4f} (+/- {scores.std()*2:.4f})")

# Несколько метрик
results = cross_validate(
    model, X, y, cv=5,
    scoring=['accuracy', 'f1', 'roc_auc'],
    return_train_score=True
)

# Стратифицированная (для классификации)
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
for train_idx, val_idx in skf.split(X, y):
    X_train, X_val = X[train_idx], X[val_idx]
    y_train, y_val = y[train_idx], y[val_idx]

# Для временных рядов
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, val_idx in tscv.split(X):
    # Обучение только на прошлых данных
    pass

Hyperparameter Tuning

from sklearn.model_selection import GridSearchCV, RandomizedSearchCV

# Grid Search (перебор всех комбинаций)
param_grid = {
    'n_estimators': [100, 200, 300],
    'max_depth': [5, 10, 15, None],
    'min_samples_split': [2, 5, 10]
}
grid_search = GridSearchCV(
    RandomForestClassifier(),
    param_grid,
    cv=5,
    scoring='f1',
    n_jobs=-1,
    verbose=1
)
grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best score: {grid_search.best_score_:.4f}")
best_model = grid_search.best_estimator_

# Random Search (быстрее для большого пространства)
from scipy.stats import randint, uniform
param_dist = {
    'n_estimators': randint(100, 500),
    'max_depth': randint(5, 50),
    'min_samples_split': randint(2, 20)
}
random_search = RandomizedSearchCV(
    RandomForestClassifier(),
    param_dist,
    n_iter=50,          # Количество комбинаций
    cv=5,
    scoring='f1',
    n_jobs=-1,
    random_state=42
)

Pipelines

from sklearn.pipeline import Pipeline, make_pipeline
from sklearn.compose import ColumnTransformer

# Простой pipeline
pipe = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', LogisticRegression())
])
pipe.fit(X_train, y_train)  # (1)!
y_pred = pipe.predict(X_test)  # (2)!

# make_pipeline (автоименование)
pipe = make_pipeline(StandardScaler(), LogisticRegression())

# Разная обработка для разных типов признаков
numeric_features = ['age', 'income']
categorical_features = ['gender', 'city']

preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features),
        ('cat', OneHotEncoder(drop='first'), categorical_features)  # (3)!
    ],
    remainder='passthrough'
)

full_pipe = Pipeline([
    ('preprocessor', preprocessor),
    ('classifier', RandomForestClassifier())
])
  1. fit() вызывает scaler.fit_transform(X_train) -> classifier.fit(X_scaled, y). Scaler учит статистики ТОЛЬКО на train.
  2. predict() вызывает scaler.transform(X_test) -> classifier.predict(X_scaled). Статистики scaler из train -- нет leakage.
  3. drop='first' убирает одну dummy-колонку для предотвращения мультиколлинеарности (dummy variable trap). Критично для LogReg, не важно для деревьев.

Metrics

Classification

from sklearn.metrics import (
    accuracy_score,
    precision_score, recall_score, f1_score,
    roc_auc_score, average_precision_score,
    confusion_matrix, classification_report,
    precision_recall_curve, roc_curve
)

# Базовые метрики
print(f"Accuracy: {accuracy_score(y_test, y_pred):.4f}")
print(f"Precision: {precision_score(y_test, y_pred):.4f}")
print(f"Recall: {recall_score(y_test, y_pred):.4f}")
print(f"F1: {f1_score(y_test, y_pred):.4f}")

# Для вероятностей
y_prob = model.predict_proba(X_test)[:, 1]
print(f"ROC-AUC: {roc_auc_score(y_test, y_prob):.4f}")
print(f"PR-AUC: {average_precision_score(y_test, y_prob):.4f}")

# Детальный отчёт
print(classification_report(y_test, y_pred))

# Confusion matrix
cm = confusion_matrix(y_test, y_pred)
# [[TN, FP],
#  [FN, TP]]

# Multiclass
f1_score(y_test, y_pred, average='macro')    # Среднее по классам
f1_score(y_test, y_pred, average='weighted') # Взвешенное по размеру
f1_score(y_test, y_pred, average='micro')    # Глобальное

Regression

from sklearn.metrics import (
    mean_squared_error,
    mean_absolute_error,
    r2_score,
    mean_absolute_percentage_error
)

print(f"MSE: {mean_squared_error(y_test, y_pred):.4f}")
print(f"RMSE: {mean_squared_error(y_test, y_pred, squared=False):.4f}")
print(f"MAE: {mean_absolute_error(y_test, y_pred):.4f}")
print(f"R2: {r2_score(y_test, y_pred):.4f}")
print(f"MAPE: {mean_absolute_percentage_error(y_test, y_pred):.4f}")

Clustering

from sklearn.metrics import (
    silhouette_score,
    calinski_harabasz_score,
    davies_bouldin_score,
    adjusted_rand_score,        # Если есть истинные метки
    normalized_mutual_info_score
)

print(f"Silhouette: {silhouette_score(X, labels):.4f}")  # [-1, 1], больше лучше
print(f"Calinski-Harabasz: {calinski_harabasz_score(X, labels):.4f}")  # больше лучше
print(f"Davies-Bouldin: {davies_bouldin_score(X, labels):.4f}")  # меньше лучше

Быстрый выбор модели

graph TD
    START{"Тип задачи?"} --> CLS["Классификация"]
    START --> REG["Регрессия"]

    CLS --> INTERP{"Интерпретируемость?"}
    INTERP -->|"Да"| INTERP_Y["LogisticRegression<br/>DecisionTree"]
    INTERP -->|"Нет"| DATA_SIZE{"Данных мало<br/>< 1000?"}
    DATA_SIZE -->|"Да"| SMALL["SVC(rbf), KNN"]
    DATA_SIZE -->|"Нет"| SPEED{"Важна скорость?"}
    SPEED -->|"Да"| FAST["RandomForest<br/>LogisticRegression"]
    SPEED -->|"Нет"| BEST["GradientBoosting<br/>XGBoost, LightGBM"]

    REG --> LINEAR{"Линейная<br/>зависимость?"}
    LINEAR -->|"Да"| MULTI{"Мультиколлинеарность?"}
    MULTI -->|"Да"| REGULARIZED["Ridge, Lasso<br/>ElasticNet"]
    MULTI -->|"Нет"| LINREG["LinearRegression"]
    LINEAR -->|"Нет"| NONLIN["RandomForest<br/>GradientBoosting<br/>XGBoost"]

    style START fill:#e8eaf6,stroke:#3f51b5
    style CLS fill:#e8f5e9,stroke:#4caf50
    style REG fill:#fff3e0,stroke:#ef6c00
    style BEST fill:#e8f5e9,stroke:#4caf50
    style NONLIN fill:#fff3e0,stroke:#ef6c00

Полезные паттерны

Feature Importance

# Для деревьев
importances = model.feature_importances_
feature_imp = pd.DataFrame({
    'feature': X.columns,
    'importance': importances
}).sort_values('importance', ascending=False)

# Permutation importance (универсальный)
from sklearn.inspection import permutation_importance
result = permutation_importance(model, X_test, y_test, n_repeats=10)

Learning Curves

from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt

train_sizes, train_scores, val_scores = learning_curve(
    model, X, y, cv=5,
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='accuracy'
)

plt.plot(train_sizes, train_scores.mean(axis=1), label='Train')
plt.plot(train_sizes, val_scores.mean(axis=1), label='Validation')
plt.xlabel('Training Size')
plt.ylabel('Score')
plt.legend()

Class Weights для дисбаланса

from sklearn.utils.class_weight import compute_class_weight

# Автоматический расчёт
weights = compute_class_weight('balanced', classes=np.unique(y), y=y)
class_weights = dict(zip(np.unique(y), weights))

model = RandomForestClassifier(class_weight='balanced')
# или
model = LogisticRegression(class_weight={0: 1, 1: 10})

Сохранение модели

import joblib

# Сохранить
joblib.dump(model, 'model.joblib')
joblib.dump(pipe, 'pipeline.joblib')

# Загрузить
model = joblib.load('model.joblib')

Самопроверка

  1. Pipeline: Напишите Pipeline для задачи классификации с: (a) StandardScaler для числовых, OneHotEncoder для категориальных (ColumnTransformer), (b) RandomForestClassifier, © GridSearchCV по 3 гиперпараметрам. Почему Pipeline предотвращает data leakage, а ручной preprocessing -- нет?

  2. Cross-validation: У вас временные ряды (цены акций за 5 лет). Почему нельзя использовать StratifiedKFold? Какой splitter правильный и почему? Напишите код.

  3. Дисбаланс: Датасет с 3% fraud. Напишите код: (a) class_weight='balanced' для LogReg, (b) сравните ROC-AUC и PR-AUC через cross_validate. Какая метрика более информативна и почему?


Источники

  1. scikit-learn -- User Guide -- официальная документация
  2. scikit-learn -- Pipeline -- ColumnTransformer и Pipeline
  3. scikit-learn -- Cross-validation -- стратегии валидации
  4. scikit-learn -- Model selection -- flowchart выбора модели

See Also