DOCODIVE
Intermediate Free Learning Path

Machine Learning Intermediate: Tuning & Advanced

Take models from good to competition-winning. Master hyperparameter tuning with Optuna, advanced cross-validation, feature engineering, imbalanced data, stacking, AutoML, and a Kaggle-style capstone.

6–8 weeks 20 lessons 1 capstone ML Beginner required
Start Learning
01

Hyperparameter Tuning Deep Dive

24 min
What you'll learn
  • Understand hyperparameters vs parameters
  • Learn the tuning workflow
  • Avoid tuning pitfalls

Parameters are learned by the model (weights); hyperparameters are set by you (max_depth, learning_rate, n_estimators). Tuning means systematically searching for the best hyperparameter combination. The danger is tuning too aggressively on a single validation set — you can overfit the validation data itself. Always use cross-validation inside your search, and hold out a final untouched test set.

tuning.py
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [None, 10, 20],
    'min_samples_split': [2, 5]
}
grid = GridSearchCV(RandomForestClassifier(), param_grid, cv=5, scoring='accuracy')
grid.fit(X_train, y_train)
print('Best:', grid.best_params_)
Live Preview
Hyperparameter Tuning Deep Dive
max_depth
n_estimators
learning_rate
🔎 Important: Tune with cross-validation, evaluate on a holdout set. Tuning on your final test set is cheating.
Try it yourself

What's the difference between a parameter and a hyperparameter?

Learned vs set.
Parameters are learned during training; hyperparameters are set before training.
02

GridSearchCV & RandomSearchCV

26 min
What you'll learn
  • Search hyperparameter grids
  • Understand exhaustive vs random
  • Pick the right strategy

GridSearchCV tries EVERY combination in your grid — thorough but explodes exponentially as you add parameters. RandomSearchCV samples random combinations — less exhaustive but far more efficient in high dimensions, and research shows it often finds equally good solutions in less time. Rule of thumb: small grids → GridSearch; large search spaces → RandomSearch.

search.py
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV

# Exhaustive
param_grid = {'max_depth': [3, 5, 10], 'n_estimators': [50, 100]}
grid = GridSearchCV(model, param_grid, cv=5)

# Random
param_dist = {'max_depth': list(range(1, 20)), 'n_estimators': list(range(10, 500))}
random = RandomizedSearchCV(model, param_dist, n_iter=30, cv=5, random_state=42)
Live Preview
GridSearchCV & RandomSearchCV
d3 n50
d3 n100
d5 n50
d5 n100
d10 n100
d10 n50
💡 Tip: For 3+ hyperparameters with wide ranges, RandomSearch beats GridSearch on time AND often finds better results.
Try it yourself

When would you prefer RandomSearchCV over GridSearchCV?

Large search space.
When the hyperparameter space is too large for exhaustive search.
03

Bayesian Optimization with Optuna

28 min
What you'll learn
  • Understand Bayesian optimization
  • Use Optuna for tuning
  • Beat grid/random search

Grid and random search waste time on bad regions. Bayesian optimization learns from previous trials — it builds a model of 'which hyperparameters give good scores' and focuses search there. Optuna is the modern library for this: define an objective function, let it sample intelligently, and it converges to optimal hyperparameters in far fewer trials. This is what serious teams use.

optuna.py
import optuna

def objective(trial):
    n_estimators = trial.suggest_int('n_estimators', 10, 500)
    max_depth = trial.suggest_int('max_depth', 1, 30)
    model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth)
    return cross_val_score(model, X, y, cv=5).mean()

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=50)
print('Best:', study.best_params)
Live Preview
Bayesian Optimization with Optuna
✓ Best Practice: Optuna typically finds better hyperparameters in fewer trials than grid or random search.
Try it yourself

What makes Bayesian optimization different from grid search?

Learning from trials.
It learns from previous trials and focuses on promising regions.
04

Advanced Cross-Validation

26 min
What you'll learn
  • Use stratified and grouped CV
  • Handle time series splits
  • Pick the right CV for your data

Plain k-fold is wrong for many real datasets. StratifiedKFold preserves class proportions (critical for imbalanced data). GroupKFold keeps related samples together (patients, users — prevents leakage). TimeSeriesSplit respects chronological order (no future data in training). Using the wrong split leaks information and inflates your scores dishonestly.

cv.py
from sklearn.model_selection import StratifiedKFold, TimeSeriesSplit, GroupKFold

# Imbalanced classes -> stratify
skf = StratifiedKFold(n_splits=5)
# Time-ordered data -> chronological
tss = TimeSeriesSplit(n_splits=5)
# Related samples -> group
gkf = GroupKFold(n_splits=5)
scores = cross_val_score(model, X, y, cv=skf, groups=groups)
Live Preview
Advanced Cross-Validation
⚖️Stratified
📅TimeSeries
👥Grouped
🔎 Important: Wrong CV = data leakage = your model looks great in validation, fails in production.
Try it yourself

Which CV for time-series forecasting?

Chronological order.
TimeSeriesSplit — never use future data to train.
05

Advanced Feature Engineering

28 min
What you'll learn
  • Create interaction features
  • Use target encoding
  • Engineer domain features

Feature engineering is where domain knowledge meets ML — and it often matters more than model choice. Interaction features combine variables (price × quantity). Target encoding replaces categories with their average target value (powerful but risks leakage — must be done inside CV). Binning, ratios, and temporal aggregations all create signal. The best feature engineer beats the best algorithm.

features.py
# Interaction feature
import pandas as pd
df['price_per_unit'] = df['price'] / df['quantity']
df['income_age_ratio'] = df['income'] / (df['age'] + 1)

# Target encoding (inside CV only!)
import category_encoders as ce
encoder = ce.TargetEncoder()
X_encoded = encoder.fit_transform(X_train, y_train)
Live Preview
Advanced Feature Engineering
price / quantity → price_per_unit
income / age → income_age_ratio
target encode: city → mean_price
✓ Best Practice: Target encoding MUST happen inside cross-validation folds — encoding on full data leaks the target.
Try it yourself

Give one example of an interaction feature.

Combine two columns.
price × quantity, or age / income.
06

Handling Imbalanced Data

28 min
What you'll learn
  • Understand class imbalance
  • Use SMOTE and class weights
  • Evaluate properly

When one class dominates (fraud, rare disease), models learn to predict the majority and ignore the minority. Fixes: resample — SMOTE generates synthetic minority examples; undersample the majority; or use class_weight='balanced' so minority mistakes cost more. Critically, evaluate with precision/recall/F1, not accuracy. Imbalanced learning is a whole subfield because real-world data is rarely balanced.

imbalance.py
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier

smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)

model = RandomForestClassifier(class_weight='balanced')
model.fit(X_resampled, y_resampled)
Live Preview
Handling Imbalanced Data
⚠️ Common Mistake: Always check class balance FIRST — imbalanced data silently ruins otherwise-correct models.
Try it yourself

Why does SMOTE help?

Synthetic examples.
It creates synthetic minority examples so the model sees more of the rare class.
07

Pipelines & ColumnTransformer

28 min
What you'll learn
  • Build production-ready pipelines
  • Preprocess mixed data types
  • Prevent data leakage

Real datasets mix numeric and categorical columns needing different preprocessing. ColumnTransformer applies different transforms to different columns, and Pipeline chains preprocessing + model into one object. Together they make your workflow clean, reproducible, and leakage-proof — preprocessing is automatically applied correctly to train and test. This is the professional way to structure ML code.

pipeline.py
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import RandomForestClassifier

preprocessor = ColumnTransformer([
    ('num', StandardScaler(), ['age', 'income']),
    ('cat', OneHotEncoder(), ['city', 'job'])
])
pipeline = Pipeline([
    ('prep', preprocessor),
    ('model', RandomForestClassifier())
])
pipeline.fit(X_train, y_train)
Live Preview
Pipelines & ColumnTransformer
Scaler
Encoder
Model
✓ Best Practice: ColumnTransformer + Pipeline is the standard professional pattern — never preprocess outside it.
Try it yourself

Why does a pipeline prevent data leakage?

Fit only on train.
Preprocessing is fit only on training data and applied consistently to test.
08

Custom Transformers

24 min
What you'll learn
  • Build custom preprocessing steps
  • Use in pipelines
  • Encapsulate domain logic

Sometimes you need preprocessing scikit-learn doesn't have — a domain-specific cleaning, a custom scaling, a feature creation step. Custom transformers (classes with fit/transform) plug into pipelines seamlessly, keeping your logic encapsulated and reusable. This is how production teams encode their specific business logic into the ML workflow.

transformer.py
from sklearn.base import BaseEstimator, TransformerMixin

class LogTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None): return self
    def transform(self, X):
        return X.apply(lambda col: np.log1p(col))

pipeline = Pipeline([
    ('log', LogTransformer()),
    ('model', model)
])
Live Preview
Custom Transformers
LogTransformer
fit() / transform()
💡 Tip: Custom transformers make your preprocessing testable and reusable — fit() returns self, transform() does the work.
Try it yourself

What two methods must a transformer implement?

The sklearn pattern.
fit() and transform().
09

Model Stacking & Blending

28 min
What you'll learn
  • Combine diverse models
  • Learn stacking vs blending
  • Boost accuracy beyond ensembles

Stacking takes ensembling further: instead of voting, a meta-model learns how to best combine base models' predictions. You train diverse base models (RF, SVM, KNN), then train a meta-model on their out-of-fold predictions. Blending is a simpler version using a holdout set. Stacking frequently wins competitions because the meta-model learns which base model to trust when.

stacking.py
from sklearn.ensemble import StackingClassifier, RandomForestClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier

base_models = [
    ('rf', RandomForestClassifier()),
    ('svm', SVC(probability=True)),
    ('knn', KNeighborsClassifier())
]
stack = StackingClassifier(base_models, final_estimator=model)
stack.fit(X_train, y_train)
print(stack.score(X_test, y_test))
Live Preview
Model Stacking & Blending
RF
SVM
KNN
Meta
✓ Best Practice: Stacking works because different models make different mistakes — the meta-model learns who to trust.
Try it yourself

What's the difference between voting and stacking?

Meta-model.
Voting averages; stacking trains a meta-model on base predictions.
10

Model Calibration

24 min
What you'll learn
  • Understand calibrated probabilities
  • Detect miscalibration
  • Calibrate with Platt/isotonic

A model may predict 0.9 'probability' but be right only 60% of the time on such predictions — that's miscalibration. Calibration fixes probabilities so they reflect true likelihood, which matters for risk scores, fraud alerts, and any decision threshold. Random forests and SVMs are often miscalibrated; logistic regression is typically well-calibrated. CalibratedClassifierCV wraps a model to fix this.

calibrate.py
from sklearn.calibration import CalibratedClassifierCV
from sklearn.svm import SVC

model = CalibratedClassifierCV(SVC(), method='isotonic', cv=5)
model.fit(X_train, y_train)
probs = model.predict_proba(X_test)
Live Preview
Model Calibration

Green = calibrated, pink = raw

🔎 Important: If you use probabilities for decisions (thresholds), calibration is mandatory — raw SVM probabilities lie.
Try it yourself

What does a calibrated 0.8 probability mean?

True likelihood.
It's actually correct about 80% of the time.
11

Multi-class Strategies

22 min
What you'll learn
  • Handle 3+ classes
  • Understand OVR and OVO
  • Pick the right strategy

Binary classifiers don't directly handle 3+ classes, so strategies adapt them. One-vs-Rest (OVR): train one binary classifier per class (class vs all others). One-vs-One (OVO): train a classifier for every pair of classes. OVR is efficient; OVO is accurate for small class counts but quadratic cost. scikit-learn handles this automatically for most models, but knowing the strategy helps tune and debug.

multiclass.py
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC

model = OneVsRestClassifier(SVC())
model.fit(X_train, y_train)
pred = model.predict(X_test)
print('Classes predicted:', pred[:5])
Live Preview
Multi-class Strategies
1 vs R
2 vs R
3 vs R
💡 Tip: OVR trains n_class models; OVO trains n_class×(n_class-1)/2. OVR is usually the better default.
Try it yourself

How many models does OVO need for 5 classes?

5×4/2.
10 pairwise classifiers.
12

Time Series ML (Walk-Forward)

28 min
What you'll learn
  • Apply ML to time data
  • Use walk-forward validation
  • Engineer lag features

Applying ML to time series requires special care. Walk-forward validation trains on past data and tests on the next window — sliding forward, never peeking into the future. Lag features (yesterday's value, last week's average) turn time dependencies into features ML can learn. This hybrid 'time features + ML model' approach often beats classical forecasting on messy real-world data.

timeseries.py
# Walk-forward validation
from sklearn.model_selection import TimeSeriesSplit

tss = TimeSeriesSplit(n_splits=5)
for train_idx, test_idx in tss.split(X):
    model.fit(X[train_idx], y[train_idx])
    score = model.score(X[test_idx], y[test_idx])
    print(score)
Live Preview
Time Series ML (Walk-Forward)
⚠️ Common Mistake: NEVER shuffle time series — random splits leak future into training and give fake-high scores.
Try it yourself

What is a lag feature?

Past values.
A feature using past values (e.g., yesterday's sales) to predict today.
13

Anomaly Detection

26 min
What you'll learn
  • Detect rare events
  • Use isolation forest and OCSVM
  • Apply to fraud/outliers

Anomaly detection finds data points that don't fit the pattern. Isolation Forest isolates anomalies quickly (fewer splits to separate them). One-Class SVM learns a boundary around normal data and flags anything outside. Both are unsupervised — train on normal data, detect deviations. Applications: fraud, equipment failure, network intrusion, manufacturing defects.

anomaly.py
from sklearn.ensemble import IsolationForest

model = IsolationForest(contamination=0.05, random_state=42)
model.fit(X)
anomalies = model.predict(X)  # -1 = anomaly, 1 = normal
print('Anomalies detected:', (anomalies == -1).sum())
Live Preview
Anomaly Detection
🔎 Important: contamination is your expected anomaly rate — set it from domain knowledge.
Try it yourself

Why train anomaly detectors on normal data?

Anomalies are rare.
Anomalies are rare/unknown; learning normal patterns lets you flag deviations.
14

Dimensionality Reduction: t-SNE & UMAP

26 min
What you'll learn
  • Visualize high-dim data
  • Understand t-SNE vs UMAP
  • Preserve local structure

PCA preserves global variance but often hides clusters. t-SNE and UMAP are non-linear techniques that preserve LOCAL structure — nearby points stay nearby in 2D, revealing clusters PCA misses. They're visualization gold for exploring high-dimensional data (images, embeddings), but they're NOT for feature extraction (don't train on their output — they're for seeing, not feeding models).

umap.py
import umap

reducer = umap.UMAP(n_components=2, random_state=42)
embedding = reducer.fit_transform(X)
print('Embedding shape:', embedding.shape)
Live Preview
Dimensionality Reduction: t-SNE & UMAP
💡 Tip: Use t-SNE/UMAP to SEE structure, not to preprocess for training — distances are distorted.
Try it yourself

t-SNE preserves what kind of structure?

Nearby points.
Local structure — neighboring points stay neighbors.
15

AutoML Basics

24 min
What you'll learn
  • Automate model selection
  • Use AutoGluon/auto-sklearn
  • Understand when AutoML helps

AutoML automates the tedious parts — trying dozens of models, tuning hyperparameters, building ensembles — and returns the best. Libraries like AutoGluon and auto-sklearn can beat hand-tuned models on many tabular tasks in minutes. AutoML is a baseline accelerator: use it to get a strong starting model quickly, then improve from there. It doesn't replace understanding, but it saves enormous time.

automl.py
from autogluon.tabular import TabularPredictor

predictor = TabularPredictor(label='target').fit(train_df)
predictions = predictor.predict(test_df)
print(predictor.leaderboard())
Live Preview
AutoML Basics
XGBoost0.94
LightGBM0.93
RandomForest0.91
✓ Best Practice: AutoML gives you a strong baseline in minutes — then you know what to beat with hand-tuning.
Try it yourself

Is AutoML a replacement for ML understanding?

It's a tool.
No — it accelerates baseline building; understanding is still needed.
16

Model Selection Strategy

24 min
What you'll learn
  • Choose among many models
  • Use a systematic process
  • Avoid selection bias

With dozens of algorithms, choosing is overwhelming. A systematic strategy: start simple (logistic regression, decision tree) as baselines, try ensembles (random forest) next, then gradient boosting (XGBoost/LightGBM) — the usual winner on tabular data. Compare with cross-validation, pick top few, tune them, and ensemble the best. This disciplined process beats random trial-and-error.

selection.py
models = {
    'Logistic': LogisticRegression(),
    'Tree': DecisionTreeClassifier(),
    'RF': RandomForestClassifier(),
    'XGB': XGBClassifier(eval_metric='logloss')
}
for name, m in models.items():
    score = cross_val_score(m, X, y, cv=5).mean()
    print(f'{name}: {score:.3f}')
Live Preview
Model Selection Strategy
✓ Best Practice: Start simple, always try gradient boosting, and pick by cross-validation — not by intuition.
Try it yourself

What's usually the strongest model for tabular data?

Tree ensemble.
Gradient boosting (XGBoost/LightGBM).
17

Data Leakage & How to Avoid It

26 min
What you'll learn
  • Recognize leakage
  • Identify common leakage sources
  • Prevent it structurally

Leakage is when training data accidentally contains information about the target that won't be available at prediction time — future data, target encoding done wrong, preprocessing fit on the full dataset. The result: great validation scores, terrible production performance. Leakage is the #1 silent killer of ML projects. Prevention: pipelines, proper CV, and never touching test data until the very end.

leakage.py
# LEAKAGE BUG (never do this)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)  # fit on ALL data incl test

# CORRECT (inside pipeline, fit on train only)
pipeline = Pipeline([('scaler', StandardScaler()), ('model', model)])
pipeline.fit(X_train, y_train)
Live Preview
Data Leakage & How to Avoid It
⚠️
Leakage: fit on all

Pipeline: train only
⚠️ Common Mistake: If validation score looks too good to be true, suspect leakage before celebrating.
Try it yourself

Name one common source of leakage.

Preprocessing.
Fitting preprocessing on the full dataset (including test).
18

Ensemble Tuning

26 min
What you'll learn
  • Tune ensemble hyperparameters
  • Balance diversity and strength
  • Squeeze maximum performance

Tuning an ensemble is different from tuning a single model — you're balancing individual model strength against diversity. More estimators reduces variance but has diminishing returns; deeper trees add strength but reduce diversity. The art is finding the combination that maximizes the ensemble's collective accuracy. Techniques: tune base model individually, then tune ensemble aggregation.

ensemble_tune.py
param_grid = {
    'n_estimators': [100, 200, 500],
    'max_features': ['sqrt', 'log2', None],
    'max_depth': [None, 10, 20],
    'min_samples_leaf': [1, 2, 4]
}
grid = RandomizedSearchCV(RandomForestClassifier(), param_grid, n_iter=50, cv=5)
grid.fit(X, y)
Live Preview
Ensemble Tuning
n=100
n=200
n=500
💡 Tip: max_features and min_samples_leaf are the underrated knobs that control diversity.
Try it yourself

What does n_estimators control in a forest?

Tree count.
The number of trees — more reduces variance with diminishing returns.
19

Model Compression

24 min
What you'll learn
  • Shrink models for production
  • Use pruning and quantization
  • Speed up inference

Big models are expensive to deploy. Compression shrinks them: pruning removes low-importance tree branches, quantization reduces numerical precision (float32 → int8), and distillation trains a small 'student' model on a big 'teacher's' predictions. For tree ensembles, limiting depth and feature count already compresses. Smaller models = faster inference, lower memory, cheaper serving.

compress.py
# Compress via depth limiting + feature subsampling
compact = RandomForestClassifier(
    n_estimators=50,
    max_depth=5,
    max_features='sqrt'
)
compact.fit(X_train, y_train)
print('Size vs accuracy trade-off balanced')
Live Preview
Model Compression
Big
50MB
Small
12MB
💡 Tip: A 50-tree depth-5 forest often matches a 500-tree full-depth forest at a fraction of the cost.
Try it yourself

Why compress ML models?

Deployment cost.
Faster inference, lower memory, cheaper cloud serving.
20

Capstone: Kaggle-Style Project

60 min
What you'll learn
  • Apply the complete tuned ML pipeline
  • Compete against a leaderboard
  • Ship a documented solution

Your capstone: a Kaggle-style competition project. You'll build a full solution — load data, engineer features, build pipelines, tune with Optuna, stack models, validate with proper CV (avoiding leakage), and document your approach. This mirrors exactly how winning Kaggle solutions are built and is the strongest possible portfolio piece for ML roles.

capstone.py
pipeline = Pipeline([
    ('prep', preprocessor),
    ('model', StackingClassifier([
        ('rf', RandomForestClassifier()),
        ('xgb', XGBClassifier(eval_metric='logloss')),
        ('svm', SVC(probability=True))
    ]))
])
study = optuna.create_study(direction='maximize')
study.optimize(lambda t: objective(t, pipeline, X, y), n_trials=50)
print('Final best score:', study.best_value)
Live Preview
Capstone: Kaggle-Style Project
Stacked 0.965
XGB 0.93
✓ Best Practice: This is the complete professional workflow — ship it and you're ready for real ML work.
Try it yourself

What's the final step before submitting to a Kaggle leaderboard?

Check leakage.
Verify no data leakage — your validation must reflect true generalization.
You've completed all 20 intermediate lessons. Ready for advanced?

Continue to Machine Learning Advanced for deep learning, NLP, and deployment.

📱 Scan this QR code with your phone camera to instantly open this page.

Works on iOS, Android, and any modern device. No app installation required.

Account Verified!

Your email has been verified successfully.