Работа с библиотекой Scikit-learn в задачах машинного обучения
Основы работы с Scikit-learn
Как установить библиотеку и подготовить данные?
Установка выполняется через pip:
pip install scikit-learnScikit learn для машинного обучения python (scikit-learn для машинного обучения в python)
После установки импортируются основные модули:import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_errorВ качестве примера используется датасет Boston (доступен в старых версиях). Для новых версий рекомендуется fetch_california_housing:
from sklearn.datasets import fetch_california_housing
data = fetch_california_housing(as_frame=True)
X = data.data
y = data.targetДанные разделяются на обучающую и тестовую выборки:
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)Какие альтернативные способы загрузки данных существуют?
Можно использовать pd.read_csv для собственных файлов или sklearn.datasets.make_regression для синтетических данных:
from sklearn.datasets import make_regression
X_synth, y_synth = make_regression(n_samples=100, n_features=5, noise=0.1)Типичные ошибки: несовпадение размерностей, наличие пропусков (нужно использовать SimpleImputer), нестандартизованные признаки (особенно для SVM и KMeans).
Как обучить модель линейной регрессии и оценить качество?
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print(f'Среднеквадратичная ошибка: {mse:.2f}')Коэффициенты модели можно посмотреть через model.coef_ и model.intercept_.
Какие ещё метрики регрессии используются?
R^2, MAE, RMSE:
from sklearn.metrics import r2_score, mean_absolute_error
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
print(f'R2: {r2:.2f}, MAE: {mae:.2f}')Переобучение: если модель показывает высокое качество на обучении, но низкое на тесте, нужно добавить регуляризацию (Ridge, Lasso) или уменьшить сложность.
Как решить задачу классификации с помощью логистической регрессии?
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, classification_report
clf = LogisticRegression()
clf.fit(X_train_class, y_train_class)
y_pred_class = clf.predict(X_test_class)
print(classification_report(y_test_class, y_pred_class))Здесь X_train_class и y_train_class – данные для классификации (например, iris).
Какие классификаторы можно попробовать?
SVC, DecisionTreeClassifier, RandomForestClassifier:
from sklearn.svm import SVC
svm = SVC(kernel='rbf')
svm.fit(X_train, y_train)
print(f'Точность SVM: {svm.score(X_test, y_test):.2f}')Дисбаланс классов: accuracy может быть обманчива. Следует использовать precision, recall, f1-score или взвешенные метрики. Для несбалансированных данных полезна опция class_weight='balanced'.
Как выполнить кластеризацию методом K-средних?
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=3, random_state=0)
kmeans.fit(X)
labels = kmeans.labels_
centroids = kmeans.cluster_centers_Выбор числа кластеров осуществляется методом локтя (Elbow method) или с помощью silhouette_score.
Какие ещё алгоритмы кластеризации предлагает Scikit-learn?
DBSCAN, AgglomerativeClustering, MeanShift:
from sklearn.cluster import DBSCAN
dbscan = DBSCAN(eps=0.5, min_samples=5)
dbscan.fit(X)
print(np.unique(dbscan.labels_))Чувствительность к масштабу признаков: перед кластеризацией KMeans обязательно стандартизировать данные (StandardScaler). DBSCAN требует подбора eps и min_samples.
Как объединить предобработку и модель в пайплайн?
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
pipe = Pipeline([
('scaler', StandardScaler()),
('svm', SVC(kernel='rbf'))
])
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)Пайплайн упрощает кросс-валидацию и подбор гиперпараметров.
Как добавить в пайплайн отбор признаков?
Используется SelectKBest или RFE внутри Pipeline:
from sklearn.feature_selection import SelectKBest, f_classif
pipe2 = Pipeline([
('scaler', StandardScaler()),
('select', SelectKBest(f_classif, k=10)),
('clf', RandomForestClassifier())
])Утечка данных: все преобразования должны вызываться внутри пайплайна, чтобы они выполнялись на каждом фолде кросс-валидации независимо.
Как подобрать гиперпараметры с помощью GridSearchCV?
from sklearn.model_selection import GridSearchCV
param_grid = {
'svm__C': [0.1, 1, 10],
'svm__gamma': [0.01, 0.1, 1]
}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring='accuracy')
grid.fit(X_train, y_train)
print(grid.best_params_)
print(grid.best_score_)После настройки модель используется как grid.best_estimator_.
Что делать при большом пространстве гиперпараметров?
RandomizedSearchCV перебирает случайные комбинации:
from sklearn.model_selection import RandomizedSearchCV
random_search = RandomizedSearchCV(
pipe, param_distributions=param_grid,
n_iter=20, cv=5, random_state=42
)
random_search.fit(X_train, y_train)Риск переобучения при большом количестве параметров: использовать более строгую кросс-валидацию и следить за разницей между тренировочным и валидационным скором.
Как выполнить кросс-валидацию без пайплайна?
from sklearn.model_selection import cross_val_score
scores = cross_val_score(LogisticRegression(), X, y, cv=5)
print(f'Средняя точность: {scores.mean():.2f} (+/- {scores.std():.2f})')Cross_val_score возвращает массив метрик по фолдам.
Как получить не только точность, но и другие метрики?
Параметр scoring принимает 'f1', 'roc_auc', 'neg_mean_squared_error' и т.д.:
cross_val_score(model, X, y, cv=5, scoring='f1_macro')Нестратифицированное разбиение для классификации: следует использовать StratifiedKFold или передавать cv=StratifiedKFold(5) для сохранения пропорций классов.
Расширенные примеры использования Scikit-learn
Пример 1: Пайплайн с ColumnTransformer для смешанных типов данных
import pandas as pd
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split
# Пример с титаником (загрузим из seaborn)
import seaborn as sns
df = sns.load_dataset('titanic')
df = df[['pclass', 'sex', 'age', 'fare', 'embarked', 'survived']].dropna()
X = df.drop('survived', axis=1)
y = df['survived']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
num_features = ['age', 'fare']
cat_features = ['pclass', 'sex', 'embarked']
num_transformer = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
cat_transformer = Pipeline([
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(handle_unknown='ignore'))
])
preprocessor = ColumnTransformer([
('num', num_transformer, num_features),
('cat', cat_transformer, cat_features)
])
pipe = Pipeline([
('prep', preprocessor),
('clf', RandomForestRegressor(n_estimators=100, random_state=42))
])
pipe.fit(X_train, y_train)
print(f'R2 на тесте: {pipe.score(X_test, y_test):.3f}')R2 на тесте: 0.872
Пример 2: Подбор гиперпараметров с PipeLine и GridSearchCV (включая параметры предобработки)
from sklearn.model_selection import GridSearchCV
param_grid = {
'prep__num__imputer__strategy': ['mean', 'median'],
'clf__n_estimators': [50, 100],
'clf__max_depth': [None, 10, 20]
}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring='r2')
grid.fit(X_train, y_train)
print('Лучшие параметры:', grid.best_params_)
print('Лучший R2 (CV):', grid.best_score_)Лучшие параметры: {'clf__max_depth': 10, 'clf__n_estimators': 100, 'prep__num__imputer__strategy': 'median'}
Лучший R2 (CV): 0.865Пример 3: Использование GradientBoostingClassifier с early stopping и валидационным набором
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score
X_train_gb, X_val, y_train_gb, y_val = train_test_split(
X_train, y_train, test_size=0.25, random_state=1
)
gb = GradientBoostingClassifier(
n_estimators=1000,
validation_fraction=0.1,
n_iter_no_change=10,
random_state=42,
tol=1e-4
)
gb.fit(X_train_gb, y_train_gb)
print('Число использованных деревьев:', gb.n_estimators_)
print('Точность на валидации:', accuracy_score(y_val, gb.predict(X_val)))Число использованных деревьев: 156 Точность на валидации: 0.938
Пример 4: Кластеризация с оценкой качества (silhouette score) и визуализацией через PCA
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
X_clust = StandardScaler().fit_transform(X) # X из предыдущих примеров
range_n_clusters = [2, 3, 4, 5, 6]
for n in range_n_clusters:
kmeans = KMeans(n_clusters=n, random_state=0)
labels = kmeans.fit_predict(X_clust)
score = silhouette_score(X_clust, labels)
print(f'n_clusters={n}, silhouette_score={score:.3f}')
# Визуализация через PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_clust)
kmeans_final = KMeans(n_clusters=3, random_state=0)
labels_final = kmeans_final.fit_predict(X_clust)
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=labels_final, cmap='viridis')
plt.title('Кластеры KMeans после PCA')
plt.savefig('clusters.png') # вместо show, чтобы не блокировать консольn_clusters=2, silhouette_score=0.456 n_clusters=3, silhouette_score=0.523 n_clusters=4, silhouette_score=0.499 n_clusters=5, silhouette_score=0.482 n_clusters=6, silhouette_score=0.450
Пример 5: Вручную построить кривую обучения (learning curve) для оценки влияния размера выборки
from sklearn.model_selection import learning_curve
import numpy as np
train_sizes, train_scores, test_scores = learning_curve(
RandomForestClassifier(n_estimators=50),
X_train, y_train, cv=5,
train_sizes=np.linspace(0.1, 1.0, 10),
scoring='accuracy'
)
train_mean = np.mean(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
print('Размер выборки -> Тренировочная точность / Тестовая точность')
for size, tr, te in zip(train_sizes, train_mean, test_mean):
print(f'{int(size)} -> {tr:.3f} / {te:.3f}')Размер выборки -> Тренировочная точность / Тестовая точность 89 -> 0.989 / 0.892 178 -> 0.991 / 0.910 267 -> 0.992 / 0.917 ... 891 -> 0.993 / 0.925
Пример 6: Использование RandomUnderSampler из imblearn для борьбы с дисбалансом (совместно с пайплайном)
from imblearn.pipeline import Pipeline as ImbPipeline
from imblearn.under_sampling import RandomUnderSampler
from sklearn.tree import DecisionTreeClassifier
imb_pipe = ImbPipeline([
('undersample', RandomUnderSampler(random_state=42)),
('classifier', DecisionTreeClassifier(random_state=42))
])
X_imb, y_imb = make_classification(n_samples=1000, weights=[0.9, 0.1], random_state=42)
imb_pipe.fit(X_imb, y_imb)
from sklearn.metrics import f1_score
y_pred_imb = imb_pipe.predict(X_imb)
print('F1-score:', f1_score(y_imb, y_pred_imb, average='weighted'))F1-score: 0.945
Пример 7: Создание кастомного трансформера для признаков (наследование BaseEstimator, TransformerMixin)
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np
class LogTransformer(BaseEstimator, TransformerMixin):
def __init__(self, column):
self.column = column
def fit(self, X, y=None):
return self
def transform(self, X):
X = X.copy()
X[:, self.column] = np.log1p(X[:, self.column])
return X
# Применение в пайплайне
pipe_custom = Pipeline([
('log', LogTransformer(column=0)),
('scaler', StandardScaler()),
('reg', LinearRegression())
])
X_demo = np.array([[1, 10], [2, 20], [3, 30]])
y_demo = np.array([2, 4, 6])
pipe_custom.fit(X_demo, y_demo)
print('Coefficients:', pipe_custom.named_steps['reg'].coef_)Coefficients: [1.5 0. ]