Какие принципы machine learning использовал при реализации с нуля?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Принципы Machine Learning при реализации с нуля
При разработке ML-систем с нуля нужно следовать проверенным принципам, которые обеспечивают надёжность, масштабируемость и воспроизводимость результатов.
1. Разделение данных: Train/Validation/Test
Основной принцип — никогда не обучайте и не оценивайте на одних и тех же данных:
from sklearn.model_selection import train_test_split
import numpy as np
# Загружаем данные
X = load_data() # Features
y = load_labels() # Labels
# Шаг 1: Отделяем тестовый набор (20% данных)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Шаг 2: Отделяем validation набор из обучающих данных (25% = 20% от всех)
X_train, X_val, y_train, y_val = train_test_split(
X_train, y_train, test_size=0.25, random_state=42
)
print(f'Train: {len(X_train)}, Validation: {len(X_val)}, Test: {len(X_test)}')
Правило:
- Train set — обучение модели (60-70%)
- Validation set — выбор гиперпараметров, ранняя остановка (15-20%)
- Test set — ФИНАЛЬНАЯ оценка, используется только один раз (15-20%)
2. Нормализация и масштабирование данных
Большинство алгоритмов требуют одинаковый масштаб признаков:
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from sklearn.pipeline import Pipeline
# StandardScaler: (x - mean) / std — для нормального распределения
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # Fit только на train!
X_val_scaled = scaler.transform(X_val) # Transform используя train stats
X_test_scaled = scaler.transform(X_test) # То же для test
# MinMaxScaler: (x - min) / (max - min) — для [0, 1] диапазона
scaler = MinMaxScaler(feature_range=(0, 1))
# Правильный способ с Pipeline
pipeline = Pipeline([
('scaler', StandardScaler()),
('model', RandomForestClassifier())
])
pipeline.fit(X_train, y_train)
score = pipeline.score(X_test, y_test)
ВАЖНО: Масштабируем только на train данных, потом применяем к val/test!
3. Классовый баланс и стратификация
Для несбалансированных данных используем стратификацию:
from sklearn.model_selection import StratifiedKFold
from imblearn.over_sampling import SMOTE
# Стратификация: сохраняем распределение классов во всех наборах
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=42
)
print(f'Train распределение: {np.bincount(y_train)}')
print(f'Test распределение: {np.bincount(y_test)}')
# Для сильно несбалансированных данных используем SMOTE
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_train_balanced, y_train_balanced = smote.fit_resample(X_train, y_train)
print(f'Balanced: {np.bincount(y_train_balanced)}')
# Или используем class_weight в модели
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(
class_weight='balanced', # Автоматическая балансировка весов
random_state=42
)
4. Кросс-валидация
Не полагайтесь на один сплит данных:
from sklearn.model_selection import cross_val_score, KFold, StratifiedKFold
# K-Fold кросс-валидация
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(
RandomForestClassifier(),
X_train, y_train,
cv=kfold,
scoring='accuracy'
)
print(f'CV Scores: {scores}')
print(f'Mean: {scores.mean():.4f} +/- {scores.std():.4f}')
# Стратифицированная кросс-валидация для несбалансированных данных
stratified_kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(
RandomForestClassifier(),
X_train, y_train,
cv=stratified_kfold,
scoring='f1_weighted'
)
5. Правильный выбор метрик
Не всегда accuracy — правильная метрика:
from sklearn.metrics import (
accuracy_score, precision_score, recall_score, f1_score,
roc_auc_score, confusion_matrix, classification_report
)
y_pred = model.predict(X_test)
y_pred_proba = model.predict_proba(X_test)[:, 1]
# Классификация
print('=== Классификация ===')
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 Score: {f1_score(y_test, y_pred):.4f}') # Гармоническое среднее
print(f'ROC-AUC: {roc_auc_score(y_test, y_pred_proba):.4f}')
print('\n=== Матрица ошибок ===')
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))
# Регрессия
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
print('=== Регрессия ===')
print(f'MAE: {mean_absolute_error(y_test, y_pred):.4f}')
print(f'RMSE: {np.sqrt(mean_squared_error(y_test, y_pred)):.4f}')
print(f'R2: {r2_score(y_test, y_pred):.4f}')
6. Hyperparameter Tuning
Найдите оптимальные параметры модели:
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
# GridSearchCV — перебирает все комбинации
param_grid = {
'n_estimators': [10, 50, 100, 200],
'max_depth': [5, 10, None],
'min_samples_split': [2, 5, 10],
'learning_rate': [0.01, 0.1, 0.2]
}
grid_search = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid,
cv=5,
scoring='f1_weighted',
n_jobs=-1, # Параллельно
verbose=1
)
grid_search.fit(X_train, y_train)
print(f'Best params: {grid_search.best_params_}')
print(f'Best CV score: {grid_search.best_score_:.4f}')
# Используем лучшую модель
best_model = grid_search.best_estimator_
test_score = best_model.score(X_test, y_test)
print(f'Test score: {test_score:.4f}')
# RandomizedSearchCV — случайно выбирает комбинации (быстрее для больших пространств)
random_search = RandomizedSearchCV(
RandomForestClassifier(random_state=42),
param_distributions=param_grid,
n_iter=20,
cv=5,
n_jobs=-1,
random_state=42
)
7. Feature Engineering и Selection
Правильные признаки — залог успеха:
from sklearn.preprocessing import PolynomialFeatures
from sklearn.feature_selection import SelectKBest, f_classif, RFE
# Полиномиальные признаки
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X_train)
# SelectKBest — выбираем K лучших признаков
selector = SelectKBest(score_func=f_classif, k=10)
X_selected = selector.fit_transform(X_train, y_train)
support = selector.get_support()
feature_names = np.array(feature_names)[support]
print(f'Selected features: {feature_names}')
# RFE — рекурсивное исключение признаков
from sklearn.ensemble import RandomForestClassifier
rfe = RFE(RandomForestClassifier(random_state=42), n_features_to_select=10)
X_rfe = rfe.fit_transform(X_train, y_train)
# Feature importance
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)
importances = model.feature_importances_
top_indices = np.argsort(importances)[-10:]
print(f'Top 10 features: {np.array(feature_names)[top_indices]}')
8. Воспроизводимость результатов
Устанавливайте random_state везде:
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
# Воспроизводимость
RANDOM_STATE = 42
np.random.seed(RANDOM_STATE)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=RANDOM_STATE, stratify=y
)
model = RandomForestClassifier(
n_estimators=100,
random_state=RANDOM_STATE
)
model.fit(X_train, y_train)
9. Мониторинг переобучения
Отслеживайте gap между train и validation:
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
train_sizes, train_scores, val_scores = learning_curve(
RandomForestClassifier(random_state=42),
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)
val_mean = np.mean(val_scores, axis=1)
plt.plot(train_sizes, train_mean, label='Train')
plt.plot(train_sizes, val_mean, label='Validation')
plt.legend()
plt.show()
# Если lines расходятся — переобучение
10. Сохранение и воспроизведение модели
import pickle
import joblib
# Сохранение
with open('model.pkl', 'wb') as f:
pickle.dump(model, f)
# Или более быстро
joblib.dump(model, 'model.pkl')
# Загрузка
model = joblib.load('model.pkl')
# Сохранение версии
model_version = {
'model': model,
'scaler': scaler,
'feature_names': feature_names,
'hyperparameters': grid_search.best_params_,
'metrics': {'accuracy': 0.95, 'f1': 0.93},
'timestamp': datetime.now().isoformat()
}
joblib.dump(model_version, 'model_v1.0.pkl')
11. Лучшие практики
- Начните просто — baseline модель до усложнения
- Разделяйте данные — train/val/test отдельно
- Нормализуйте только на train — потом применяйте к val/test
- Проверяйте баланс классов — используйте стратификацию
- Кросс-валидируйте — не полагайтесь на один сплит
- Выбирайте правильные метрики — не только accuracy
- Тюните гиперпараметры — на validation, не на test
- Отслеживайте переобучение — смотрите gap между train и val
- Документируйте всё — версию модели, параметры, метрики
- Воспроизводимость — используйте random_state везде
Эти принципы критичны для разработки надёжных ML-систем в продакшене.