Scikit-Learn
Scikit-Learn — библиотека классического машинного обучения: регрессия, классификация, кластеризация, метрики и пайплайны. Единый интерфейс fit/transform/predict.
1. Что такое Scikit-Learn
Scikit-Learn строит ML-пайплайны: модели обучаются методом fit(X, y), предсказывают predict(X), оцениваются метриками. Вход — матрица признаков (NumPy/DataFrame), выход — вектор целевой переменной.
Подходит для табулярных данных; для картинок и текстов чаще используют глубокие фреймворки TensorFlow/PyTorch.
2. Установка
pip install scikit-learnfrom sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
data = load_iris()
X, y = data.data, data.target3. Тренировочные и тестовые данные
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y)4. Линейная регрессия
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
model = LinearRegression()
model.fit(X_train, y_train)
pred = model.predict(X_test)
print(model.coef_)
print(mean_squared_error(y_test, pred))5. Логистическая регрессия (классификация)
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(max_iter=1000)
clf.fit(X_train, y_train)
print(clf.score(X_test, y_test))Логистическая регрессия — модель вероятности класса; отлично работает на табулярных признаках.
6. Деревья и случайные леса
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=200, random_state=42)
rf.fit(X_train, y_train)
# важность признаков
print(rf.feature_importances_)
import pandas as pd
print(pd.Series(rf.feature_importances_, index=data.feature_names))Случайные леса хорошо работают без масштабирования и устойчивы к выбросам.
7. Метрики качества
from sklearn.metrics import accuracy_score, precision_score, \
recall_score, f1_score, confusion_matrix
acc = accuracy_score(y_test, pred)
prec = precision_score(y_test, pred, average='macro')
rec = recall_score(y_test, pred, average='macro')
f1 = f1_score(y_test, pred, average='macro')
print(confusion_matrix(y_test, pred))Для несбалансированных классов точность (accuracy) обманчива — смотри precision/recall/F1.
8. Кросс-валидация
from sklearn.model_selection import cross_val_score
scores = cross_val_score(rf, X, y, cv=5)
print(scores.mean(), scores.std())cv=5 разбивает данные на 5 частей и обучает 5 моделей — честная оценка обобщения.
9. Масштабирование признаков
from sklearn.preprocessing import StandardScaler
# подгоняем масштаб ТОЛЬКО по train, применяем к обоим
scaler = StandardScaler()
X_train_s = scaler.fit_transform(X_train)
X_test_s = scaler.transform(X_test)10. Пайплайны (Pipeline)
from sklearn.pipeline import Pipeline
from sklearn.svm import SVC
pipe = Pipeline([
('scaler', StandardScaler()),
('svc', SVC(kernel='rbf'))
])
pipe.fit(X_train, y_train)
print(pipe.score(X_test, y_test))Pipeline связывает трансформации и модель: весь процесс переносится одним объектом, включая в кросс-валидацию.
11. Подбор параметров (GridSearch)
from sklearn.model_selection import GridSearchCV
grid = {'svc__C': [0.1, 1, 10], 'svc__kernel': ['rbf', 'linear']}
gs = GridSearchCV(pipe, grid, cv=3)
gs.fit(X_train, y_train)
print(gs.best_params_)
print(gs.best_score_)Имя параметра внутри pipeline — через имя_шага__имя_атрибута.
12. Кластеризация: KMeans и DBSCAN
Кластеризация — задача обучения без учителя: разбить объекты на группы без заранее известных ответов. Она удобна для сегментации клиентов, поиска аномалий и подготовки признаков.
from sklearn.cluster import KMeans, DBSCAN
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(X)
labels = kmeans.labels_
dbscan = DBSCAN(eps=0.5, min_samples=5)
db_labels = dbscan.fit_predict(X)| Алгоритм | Когда использовать |
|---|---|
| KMeans | ровные компактные кластеры, известное число групп |
| DBSCAN | неизвестное число кластеров, выбросы, произвольная форма |
| Agglomerative | иерархия кластеров, дендрограмма |
silhouette_score. Нормализуйте признаки перед кластеризацией — см. раздел 9.13. Понижение размерности: PCA
Когда признаков сотни, модели учатся медленно и переобучаются. PCA (метод главных компонент) сжимает данные до нескольких ортогональных осей, сохраняя максимум дисперсии.
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
print(pca.explained_variance_ratio_)
print(pca.explained_variance_ratio_.cumsum())// типичный набор: 5 компонент объясняют 90% дисперсии
[0.42 0.37 0.10 0.06 0.03]- scale-признаки перед PCA обязательны: разный масштаб ломает расчёт;
- PCA применяйте к train и к test одним трансформером;
- первые компоненты часто улавливают главный фактор (размер, популярность).
14. Сохранение и объяснимость модели
Обученную модель нужно сериализовать, чтобы использовать в сервисе, и уметь объяснить её решения заказчику. Стандарт сериализации — joblib.
import joblib
joblib.dump(pipe, "model_pipeline.joblib")
loaded = joblib.load("model_pipeline.joblib")
print(loaded.predict(X_new))from sklearn.inspection import permutation_importance
importance = permutation_importance(loaded, X_test, y_test,
n_repeats=10, random_state=42)
print(dict(zip(feature_names, importance.importances_mean)))| Метод | Что объясняет |
|---|---|
| feature_importances_ | вклад признаков в ансамбль деревьев |
| permutation_importance | падение качества при перемешивании признака |
| SHAP | вклад каждого признака в каждое предсказание |
15. Категориальные признаки и ColumnTransformer
Модели понимают только числа. Поэтому строковые категории кодируют: OrdinalEncoder превращает значения в номера, OneHotEncoder — в столбцы 0/1. Для смеси числовых и категориальных признаков предусмотрен ColumnTransformer.
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
prep = ColumnTransformer([
("num", StandardScaler(), ["age", "income"]),
("cat", OneHotEncoder(), ["city", "plan"])
])
pipe = Pipeline([("prep", prep), ("clf", LogisticRegression())])
pipe.fit(X_train, y_train)Работает внутри того же Pipeline: каждая колонка получает свой трансформер, и весь процесс целиком попадает в кросс-валидацию и GridSearch из раздела 11.
min_frequency — редкие значения соберутся в одну группу.16. Несбалансированные классы
Когда одного класса 2%, модель «хитрит» и предсказывает большинство — accuracy при этом высоки. Лечится тремя способами: весами, ресемплингом выборки и правильными метриками.
model = RandomForestClassifier(class_weight="balanced")
# или ресемплинг: дублируем редкий класс
from imblearn.over_sampling import SMOTE
X_res, y_res = SMOTE(random_state=42).fit_resample(X_train, y_train)Оценивать такие модели нужно не accuracy, а precision/recall/F1 (раздел 7), и обязательно через StratifiedKFold, чтобы редкий класс попадал в каждую фолду.
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import f1_score
scores = [f1_score(y[val], model.fit(X[t], y[t]).predict(X[val]))
for t, val in StratifiedKFold(n_splits=5).split(X, y)]
print(sum(scores) / len(scores))| Метод | Суть | Когда |
|---|---|---|
| class_weight | штраф за ошибки редкого класса | быстро, без новых данных |
| oversampling | копии редких объектов (SMOTE) | мало данных редкого класса |
| undersampling | выкинуть часть большинства | огромный датасет |
17. Бустинг: HistGradientBoosting и друзья
Бустинг обучает слабые деревья последовательно: каждое следующее исправляет ошибки предыдущего. Случайный лес из раздела 6 — это бэггинг, деревья там обучаются параллельно; бустинг обычно точнее, но чувствительнее к переобучению.
from sklearn.ensemble import HistGradientBoostingClassifier
hgb = HistGradientBoostingClassifier(
learning_rate=0.1, max_iter=300, random_state=42)
hgb.fit(X_train, y_train)
print(hgb.score(X_test, y_test))learning_rate и число деревьев связаны обратно: маленький шаг требует больше итераций, но меньше переобучает. Промышленный стандарт — XGBoost, LightGBM и CatBoost: у них GPU-ускорение и честная работа с категориями.
| Машина | Сильная сторона |
|---|---|
| sklearn HistGradientBoosting | без лишних зависимостей, API sklearn |
| XGBoost | зрелость, экосистема, ранняя остановка |
| LightGBM | скорость, категориальные признаки |
| CatBoost | мало данных, много категорий |
18. MLflow и мониторинг модели
Эксперименты без фиксации бесполезны: невозможно вспомнить, какие признаки и гиперпараметры дали лучшее F1. MLflow логирует параметры, метрики и сам артефакт модели в единую базу.
import mlflow
mlflow.set_experiment("churn-v2")
with mlflow.start_run():
mlflow.log_params(grid)
mlflow.log_metric("f1", f1_score(y_test, pred))
mlflow.sklearn.log_model(model, "model")После деплоя модель живёт своей жизнью: распределение признаков «уплывает» (data drift), и качество тихо деградирует. Минимальный контроль — считать те же метрики на новых данных и сравнивать с порогом, а также следить, что не пропадают важные признаки.
# простой watchdog в сервисе
def check_drift(real_pred, y_real):
fresh = f1_score(y_real, real_pred)
return fresh > best_f1 - 0.0519. Feature engineering: из сырых данных в признаки
Качество модели чаще решают данные, а не алгоритм. Feature engineering — превращение сырых колонок в признаки, с которыми модель работает лучше: полиномы, бины, взаимодействия.
from sklearn.preprocessing import PolynomialFeatures, Binarizer
from sklearn.compose import ColumnTransformer
ct = ColumnTransformer([
('poly', PolynomialFeatures(degree=2,
interaction_only=True), ['price', 'rooms']),
('bin', Binarizer(threshold=200), ['area']),
])- полиномиальные признаки улавливают нелинейности (площадь² для цены);
- бинирование переводит непрерывные величины в диапазоны — полезно для таблиц с полом/возрастом;
- взаимодействия (цена × rooms) ловят совместные эффекты.
Осторожно с утечкой данных: все преобразования, вычисляющие статистику (StandardScaler, PolynomialFeatures без параметров), учите только на train — через Pipeline это гарантируется автоматически.
| Признак | Когда работает |
|---|---|
| полиномиальный | нелинейная зависимость |
| биновый | пороговые правила, категории интервалов |
| взаимодействие | совместный эффект двух переменных |
cross_val_score (раздел 8): прирост 1–2% — сигнал, что фичи тащут.20. Валидация для временных рядов
Простое train_test_split (со случайным перемешиванием) ломает временные ряды: модель видит «будущее» в обучении. Для дат применяем последовательные срезы.
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_idx, val_idx in tscv.split(X):
X_train, X_val = X[train_idx], X[val_idx]Принципы walk-forward валидации:
- train всегда раньше валидации по времени, перемешивания нет;
- окно обучения растёт с каждой итерацией (или скользит фиксированным);
- соблюдайте «лаг» между трейном и валидацией, если в данных есть автокорреляция (спрос, погода).
fold 1: [train 01-03] [val 04]
fold 2: [train 01-04] [val 05]
fold 3: [train 01-05] [val 06]21. Обработка пропусков: imputation
Пропущенные значения нельзя тупо удалить: строк может быть мало, а в X теряется связь. Imputation — заполнение пропусков оценкой: константой, медианой или моделью.
from sklearn.impute import SimpleImputer, IterativeImputer
SimpleImputer(strategy='median') # константа/медиана
IterativeImputer(max_iter=10) # заполнение моделью по остальным фичам| Стратегия | Плюсы | Минусы |
|---|---|---|
| константа/медиана | просто, стабильно | сдвигает распределение |
| imputation по KNN | учитывает похожие объекты | дорого на больших данных |
| IterativeImputer | использует взаимосвязи | сложный, медленный |
Важно: импьютеры должны учиться на трейне, поэтому вставляйте их в Pipeline (раздел 9). Не забывайте про признак «был ли пропуск» — MissingIndicator часто улучшает модель.
- разделите «нет данных» и «реально 0» — для них стратегии разные;
- для деревьев пропуски толерантны, для линейных моделей и KNN — нет;
- доля пропусков > 70% — возможно, колонку лучше удалить.
22. Ансамбли: стекинг и голосование
Разные модели ошибаются по-разному. Ансамбли объединяют предсказания: голосование (voting) без создания новых моделей и стекинг, где мета-модель учится на выходах базовых.
from sklearn.ensemble import VotingClassifier, StackingClassifier
from sklearn.linear_model import LogisticRegression
stack = StackingClassifier(
estimators=[('tree', DecisionTreeClassifier(max_depth=4)),
('nb', GaussianNB())],
final_estimator=LogisticRegression())
stack.fit(X_train, y_train)| Подход | Как объединяет |
|---|---|
| Voting (hard) | голосование классов поровну |
| Voting (soft) | усреднение вероятностей |
| Stacking | мета-модель учится на выходах базовых |
- базовые модели должны быть разнообразными — иначе ансамбль почти не выигрывает;
- стекинг склонен к переобучению: 5 фолдов для выхода базовых — стандарт;
- двух-трёх базовых моделей достаточно, «зоопарк» усложняет поддержку без выгоды.
Что дальше
Для глубокого обучения переходи на Keras/PyTorch. Данные готовь в Pandas, а работу веди в Jupyter.