DOCODIVE
Intermediate Free Learning Path

Data Science Intermediate: Machine Learning

Learn to build, evaluate, and tune real machine learning models with scikit-learn — regression, classification, trees, random forests, clustering, cross-validation, pipelines, and an end-to-end capstone project.

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

What Is Machine Learning?

18 min
What you'll learn
  • Define machine learning
  • Distinguish supervised and unsupervised
  • Understand the ML workflow

Machine learning is teaching computers to learn patterns from data instead of being explicitly programmed. In supervised learning, you train on labeled examples — inputs with known answers — to predict new ones. In unsupervised learning, the algorithm finds hidden structure without labels. Every ML system, from spam filters to recommendation engines, follows this core workflow: collect data, prepare it, train a model, evaluate it, then deploy it to make predictions.

ml_basics.py
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

# The canonical ML workflow
X = features  # input data
y = labels    # what to predict
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = LinearRegression()
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print(f'Accuracy: {score:.2f}')
Live Preview
What Is Machine Learning?
Data
Clean
Split
Train
Evaluate
🔎 Important: Supervised = labeled data. Unsupervised = no labels. If you know the target, it's supervised.
Try it yourself

Name two supervised and two unsupervised learning tasks.

Think about prediction vs grouping.
Supervised: spam detection, house price prediction. Unsupervised: customer segmentation, anomaly detection.
02

scikit-learn: Your ML Toolkit

16 min
What you'll learn
  • Install scikit-learn
  • Understand the estimator API
  • Use fit/predict/transform

scikit-learn is Python's most popular ML library because everything follows one consistent API: every model has fit() to train, predict() for supervised output, and transform() for preprocessing. Once you learn this pattern, you can switch between dozens of models — linear regression, random forest, SVM — with almost no extra learning. This consistency is why scikit-learn is the best starting point for ML.

sklearn.py
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()          # preprocessing: transform()
X_scaled = scaler.fit_transform(X)

model = RandomForestClassifier()   # supervised: fit/predict
model.fit(X_scaled, y)
predictions = model.predict(X_scaled)
print(predictions[:5])
Output
python
[0 1 1 0 1]
✓ Best Practice: The fit/predict/transform trio is the ENTIRE scikit-learn interface — master it once, use it everywhere.
Try it yourself

Import a RandomForestClassifier and fit it to dummy data.

from sklearn.ensemble import RandomForestClassifier; model.fit(X, y).
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(X, y)
03

Train/Test Split

18 min
What you'll learn
  • Split data for honest evaluation
  • Understand why test data must be untouched
  • Use train_test_split

If you train and test on the same data, the model can 'cheat' by memorizing answers — and fail on new data. The fix: hold out a test set the model never sees during training. train_test_split randomly divides your data (typically 80% train, 20% test). You train on the train set, evaluate on the test set, and that score tells you how the model will perform on truly new data.

split.py
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, random_state=42
)
print('Train size:', len(X_train))
print('Test size:', len(X_test))
Live Preview
Train/Test Split
Train80%
Test20%
🔎 Important: random_state makes the split reproducible — same number, same split, every time.
Try it yourself

Split data with a 30% test set.

test_size=0.3.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
04

Linear Regression

22 min
What you'll learn
  • Fit a line to data
  • Understand coefficients
  • Make numeric predictions

Linear regression finds the best straight line through your data — the relationship between input variables and a numeric output. It predicts things like prices, temperatures, and sales numbers. The model learns coefficients (slopes) for each feature and an intercept (where the line starts). Despite being simple, it's interpretable, fast, and often the first model you should try for any numeric prediction task.

regression.py
from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(X, y)
print('Coefficients:', model.coef_)
print('Intercept:', model.intercept_)
prediction = model.predict([[5]])
print('Prediction for x=5:', prediction[0])
Live Preview
Linear Regression
💡 Tip: The coefficient means: for each 1-unit increase in x, y changes by that amount.
Try it yourself

Fit a LinearRegression and print its intercept.

model.intercept_.
model = LinearRegression()
model.fit(X, y)
print(model.intercept_)
05

Feature Engineering Basics

22 min
What you'll learn
  • Understand features
  • Create new features
  • Scale and encode data

Features are the inputs your model learns from — and their quality matters more than the algorithm. Feature engineering means creating useful new features (combining, transforming, extracting), scaling numeric values so they're comparable, and encoding categories into numbers. A well-engineered simple model often beats a poorly-featured complex one. This is where domain knowledge meets ML.

features.py
from sklearn.preprocessing import StandardScaler, OneHotEncoder

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_numeric)
print('Scaled mean:', X_scaled.mean(), 'std:', X_scaled.std())
Live Preview
Feature Engineering Basics
age
income
city
✓ Best Practice: StandardScaler centers data at mean 0, std 1 — essential for models sensitive to scale (SVM, KNN, neural nets).
Try it yourself

Scale a feature matrix so it has mean 0.

StandardScaler().fit_transform(X).
from sklearn.preprocessing import StandardScaler
X_scaled = StandardScaler().fit_transform(X)
06

Handling Categorical Data

20 min
What you'll learn
  • Encode categories for ML
  • Use OneHotEncoder
  • Avoid the dummy trap

ML models need numbers, but real data has categories — 'red', 'blue', 'green'. One-hot encoding converts each category into a binary column (is_red, is_blue, is_green). This prevents the model from wrongly assuming 'green' > 'blue' (which ordinal label encoding would imply). For many categories, target encoding or embeddings may be better, but one-hot is the safe default for small cardinality.

categorical.py
from sklearn.preprocessing import OneHotEncoder

colors = [['red'], ['blue'], ['green'], ['red']]
encoder = OneHotEncoder(sparse_output=False)
encoded = encoder.fit_transform(colors)
print(encoded)
Live Preview
Handling Categorical Data
age
income
city
🔎 Important: One-hot avoids implying order: 'green' isn't 'greater than' 'red' just because it appears later.
Try it yourself

One-hot encode a column with 3 categories.

OneHotEncoder(sparse_output=False).fit_transform(...).
enc = OneHotEncoder(sparse_output=False)
X_encoded = enc.fit_transform([['a'],['b'],['c']])
07

Logistic Regression (Classification)

22 min
What you'll learn
  • Understand binary classification
  • Use logistic regression
  • Interpret probabilities

Despite the name, logistic regression is a classification model — it predicts categories, not numbers. It outputs a probability between 0 and 1 (through the sigmoid function), then applies a threshold (usually 0.5) to decide the class. It's the go-to first model for binary problems like spam/not-spam, churn/no-churn, and yes/no predictions, because it's fast, interpretable, and gives calibrated probabilities.

logistic.py
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
model.fit(X, y)
probabilities = model.predict_proba(X)
predictions = model.predict(X)
print('Probabilities:', probabilities[:3])
print('Predictions:', predictions[:3])
Live Preview
Logistic Regression (Classification)
Sample 192% class 0
Sample 285% class 1
Sample 388% class 0
💡 Tip: predict_proba gives confidence — 0.92 means the model is 92% sure. Use it, not just the class.
Try it yourself

Get probability predictions from a logistic model.

model.predict_proba(X).
probs = model.predict_proba(X)
08

Model Evaluation: Accuracy Is Not Enough

24 min
What you'll learn
  • Understand accuracy limits
  • Learn precision, recall, F1
  • Read confusion matrices

Accuracy (correct / total) sounds perfect but lies when classes are imbalanced. In fraud detection, 99% accuracy is useless if it misses every fraud case. Precision answers 'of my positives, how many were right?' Recall answers 'of actual positives, how many did I catch?' F1 balances both. The confusion matrix shows all four outcomes: true positives, true negatives, false positives, false negatives.

metrics.py
from sklearn.metrics import classification_report, confusion_matrix

y_true = [0, 1, 1, 0, 1, 0, 1, 1]
y_pred = [0, 1, 0, 0, 1, 1, 1, 1]
print(confusion_matrix(y_true, y_pred))
print(classification_report(y_true, y_pred))
Live Preview
Model Evaluation: Accuracy Is Not Enough
Pred 0
Pred 1
True 0
2
1
True 1
1
4
⚠️ Common Mistake: For imbalanced data, track precision/recall/F1 — never accuracy alone. It will mislead you.
Try it yourself

Compute a confusion matrix from true and predicted labels.

confusion_matrix(y_true, y_pred).
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_true, y_pred)
09

Overfitting & Underfitting

22 min
What you'll learn
  • Recognize overfitting
  • Recognize underfitting
  • Use regularization to fix it

Underfitting: the model is too simple and misses real patterns. Overfitting: the model is too complex and memorizes noise instead of signal. The telltale sign: great training score, terrible test score. Fixes include more data, simpler models, cross-validation, and regularization — which penalizes complexity so the model stays general. This is the single most important concept for building models that work in the real world.

overfitting.py
from sklearn.linear_model import Ridge

# Ridge adds L2 regularization
model = Ridge(alpha=1.0)
model.fit(X_train, y_train)
print('Train score:', model.score(X_train, y_train))
print('Test score:', model.score(X_test, y_test))
Live Preview
Overfitting & Underfitting

Test error rises as model memorizes

🔎 Important: A big gap between train and test score = overfitting. Regularization (alpha) closes that gap.
Try it yourself

What does a train score of 0.99 and test score of 0.60 indicate?

Big gap = ?
Overfitting — the model memorized the training data.
10

Cross-Validation

24 min
What you'll learn
  • Understand k-fold validation
  • Use cross_val_score
  • Get robust performance estimates

A single train/test split can be lucky (or unlucky). Cross-validation fixes this by splitting data into k folds, training k times — each time using a different fold as the test set — then averaging the scores. The result is a robust, honest estimate of your model's performance. 5-fold or 10-fold is standard. This is how serious ML practitioners report results.

crossval.py
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()
scores = cross_val_score(model, X, y, cv=5)
print('Scores:', scores)
print('Mean:', scores.mean(), 'Std:', scores.std())
Live Preview
Cross-Validation
✓ Best Practice: Always report mean ± std from cross-validation — not a single lucky split.
Try it yourself

Run 10-fold cross-validation on a model.

cross_val_score(model, X, y, cv=10).
scores = cross_val_score(model, X, y, cv=10)
print(scores.mean())
11

Decision Trees

22 min
What you'll learn
  • Understand tree-based decisions
  • Visualize decision rules
  • Interpret feature importance

Decision trees make predictions by asking a series of yes/no questions — 'is age > 30?', 'is income > 50k?' — until reaching a leaf with an answer. They're intuitive, require little data prep, handle both numeric and categorical features, and are fully interpretable: you can trace exactly why a prediction was made. The downside is they overfit easily, which is why ensembles (next lesson) were invented.

tree.py
from sklearn.tree import DecisionTreeClassifier

model = DecisionTreeClassifier(max_depth=3)
model.fit(X, y)
importances = model.feature_importances_
print('Feature importances:', importances)
Live Preview
Decision Trees
age > 30?
Yes → high income?
No → low risk
💡 Tip: max_depth is your overfitting control — deeper trees memorize, shallow trees generalize.
Try it yourself

Limit a decision tree to depth 2.

DecisionTreeClassifier(max_depth=2).
model = DecisionTreeClassifier(max_depth=2)
model.fit(X, y)
12

Random Forests

24 min
What you'll learn
  • Understand ensemble learning
  • Train a random forest
  • Reduce overfitting

A random forest is an ensemble of many decision trees that vote on the final answer. Each tree sees a random subset of data and features, so they make different mistakes — and averaging cancels those mistakes out. The result: higher accuracy and far less overfitting than any single tree. Random forests are the workhorse of tabular ML: strong defaults, minimal tuning, and robust to messy data.

forest.py
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
accuracy = model.score(X_test, y_test)
print(f'Accuracy: {accuracy:.3f}')
Live Preview
Random Forests
✓ Best Practice: n_estimators=100 is a solid default — more trees improve stability but have diminishing returns.
Try it yourself

Train a random forest with 200 trees.

RandomForestClassifier(n_estimators=200).
model = RandomForestClassifier(n_estimators=200)
model.fit(X, y)
13

K-Means Clustering

24 min
What you'll learn
  • Understand unsupervised learning
  • Cluster data with k-means
  • Choose the number of clusters

K-means is unsupervised — it finds natural groupings in unlabeled data. The algorithm picks k centers, assigns each point to the nearest center, moves centers to the average of their points, and repeats until stable. Use it for customer segmentation, image compression, and anomaly detection. The key question is choosing k, often done with the elbow method or domain knowledge.

kmeans.py
from sklearn.cluster import KMeans

model = KMeans(n_clusters=3, random_state=42)
model.fit(X)
labels = model.labels_
centers = model.cluster_centers_
print('Labels:', labels)
print('Centers:', centers)
Live Preview
K-Means Clustering
🔎 Important: Scale your data BEFORE k-means — it's distance-based, so unscaled features dominate the result.
Try it yourself

Cluster data into 5 groups with k-means.

KMeans(n_clusters=5).
model = KMeans(n_clusters=5)
model.fit(X)
labels = model.labels_
14

The Elbow Method

18 min
What you'll learn
  • Choose optimal k
  • Plot inertia
  • Find the elbow point

How many clusters should you pick? The elbow method runs k-means for several k values and plots inertia (how tightly packed the clusters are). Inertia always drops as k increases, but the 'elbow' — where the drop suddenly slows — suggests the natural number of clusters. More clusters than the elbow often splits real groups; fewer lumps them together.

elbow.py
from sklearn.cluster import KMeans

inertias = []
for k in range(1, 8):
    model = KMeans(n_clusters=k, random_state=42)
    model.fit(X)
    inertias.append(model.inertia_)
print(inertias)
Live Preview
The Elbow Method

Elbow at k=3

💡 Tip: The elbow is where the curve bends sharply — here around k=3 (400→250 is the big drop).
Try it yourself

What does a sharp elbow at k=4 suggest?

Natural clusters.
The data likely has 4 natural clusters.
15

Handling Imbalanced Data

24 min
What you'll learn
  • Recognize class imbalance
  • Use SMOTE to oversample
  • Use class weights

Imbalanced data means one class vastly outnumbers another — 99% normal transactions, 1% fraud. A model that always predicts 'normal' gets 99% accuracy but is useless. Fixes: oversample the minority (SMOTE creates synthetic examples), undersample the majority, or use class_weight='balanced' so the model pays more attention to rare classes. Fraud, rare disease, and churn all need this.

imbalance.py
from sklearn.ensemble import RandomForestClassifier

# class_weight makes minority class mistakes cost more
model = RandomForestClassifier(class_weight='balanced', random_state=42)
model.fit(X_train, y_train)
print('Minority recall:', model.score(X_test, y_test))
Live Preview
Handling Imbalanced Data
⚠️ Common Mistake: Always check class balance BEFORE building a classifier — it changes everything about evaluation.
Try it yourself

Add class_weight='balanced' to a logistic regression.

LogisticRegression(class_weight='balanced').
model = LogisticRegression(class_weight='balanced')
model.fit(X, y)
16

Pipelines for Clean ML Workflows

22 min
What you'll learn
  • Chain preprocessing and model
  • Avoid data leakage
  • Streamline training

A Pipeline chains preprocessing steps and the model into one object — so scaling, encoding, and training happen together, consistently. This prevents the #1 ML bug: data leakage, where you accidentally fit preprocessing on the test data. With a pipeline, every step is applied correctly to train and test separately, and your whole workflow is one clean, reusable object.

pipeline.py
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', LogisticRegression())
])
pipeline.fit(X_train, y_train)
score = pipeline.score(X_test, y_test)
print(f'Pipeline score: {score:.3f}')
Live Preview
Pipelines for Clean ML Workflows
Scaler
Encoder
Model
✓ Best Practice: Pipelines make leakage nearly impossible — preprocessing is always fit only on training data.
Try it yourself

Build a pipeline with scaling then a decision tree.

Pipeline([('scaler', StandardScaler()), ('model', DecisionTreeClassifier())]).
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', DecisionTreeClassifier())
])
17

Hyperparameter Tuning with GridSearchCV

26 min
What you'll learn
  • Understand hyperparameters
  • Use GridSearchCV
  • Find the best model config

Models have dials — hyperparameters like max_depth or n_estimators — and tuning them can meaningfully improve performance. GridSearchCV systematically tries every combination in a grid, evaluates each with cross-validation, and returns the best. It's brute force but reliable. RandomSearchCV samples random combos and is better when the search space is large.

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

param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [None, 5, 10]
}
grid = GridSearchCV(RandomForestClassifier(), param_grid, cv=5)
grid.fit(X, y)
print('Best params:', grid.best_params_)
print('Best score:', grid.best_score_)
Output
python
Best params: {'max_depth': 10, 'n_estimators': 100} Best score: 0.93
💡 Tip: GridSearchCV itself uses cross-validation — so you're tuning with robust estimates, not luck.
Try it yourself

Tune max_depth over [3, 5, 10] for a decision tree.

param_grid = {'max_depth': [3,5,10]}.
grid = GridSearchCV(DecisionTreeClassifier(), {'max_depth':[3,5,10]}, cv=5)
grid.fit(X, y)
18

Model Interpretability: What Drives Predictions?

22 min
What you'll learn
  • Understand why models predict what they do
  • Use feature importance
  • Build trust in ML

A model that works but can't be explained is dangerous — especially in healthcare, finance, and hiring. Interpretability means knowing which features drive predictions. Tree models give feature_importances_ directly. For any model, permutation importance shuffles a feature and measures how much the score drops. Explaining models builds trust, catches bias, and satisfies regulatory requirements.

interpret.py
from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier()
model.fit(X, y)
importances = model.feature_importances_
for name, imp in zip(feature_names, importances):
    print(f'{name}: {imp:.3f}')
Live Preview
Model Interpretability: What Drives Predictions?
age
income
city
🔎 Important: If a gender column has high importance, that's a red flag — you may have embedded bias.
Try it yourself

Print feature importances from a random forest.

model.feature_importances_.
print(model.feature_importances_)
19

Saving & Loading Models

16 min
What you'll learn
  • Persist trained models
  • Use joblib
  • Deploy models to production

Training a model is expensive — you don't want to redo it every time. joblib saves a trained model to disk, and you load it later to make predictions instantly. This is how models go to production: train once (offline), save, load (online) when serving predictions. Without this, your ML work stays stuck in a notebook.

save.py
import joblib

# Save
model.fit(X, y)
joblib.dump(model, 'model.joblib')

# Load
loaded_model = joblib.load('model.joblib')
prediction = loaded_model.predict([[5]])
print('Prediction:', prediction)
Output
python
Prediction: [1]
✓ Best Practice: joblib is the scikit-learn standard for saving — pickle also works but joblib is faster for big models.
Try it yourself

Save and reload a model with joblib.

joblib.dump(model, 'm.joblib'); joblib.load('m.joblib').
joblib.dump(model, 'model.joblib')
model2 = joblib.load('model.joblib')
20

Capstone: End-to-End ML Project

50 min
What you'll learn
  • Apply the full ML workflow
  • Clean, split, train, evaluate
  • Tune and save a production model

Your capstone: a complete ML project from raw data to a saved model. Load a dataset, clean it, engineer features, split train/test, build a pipeline, tune with GridSearchCV, evaluate with cross-validation, interpret feature importances, and save the final model. This is the exact workflow a data scientist does on the job — and it's portfolio-ready.

capstone.py
import pandas as pd
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

df = pd.read_csv('data.csv')
X, y = df.drop('target', axis=1), df['target']

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', RandomForestClassifier())
])
param_grid = {'model__n_estimators': [50, 100], 'model__max_depth': [5, 10]}
grid = GridSearchCV(pipeline, param_grid, cv=5)
grid.fit(X, y)
print('Best:', grid.best_score_)
joblib.dump(grid.best_estimator_, 'final_model.joblib')
Live Preview
Capstone: End-to-End ML Project
Scaler
Encoder
Model
✓ Best Practice: This single project proves you can do the job — ship it, share it, and you're ready.
Try it yourself

Add a StandardScaler to your pipeline before the model.

Pipeline([('scaler', StandardScaler()), ('model', ...)]).
pipeline = Pipeline([('scaler', StandardScaler()), ('model', RandomForestClassifier())])
You've completed all 20 ML lessons. Ready for advanced?

Continue to Data Science Advanced for deep learning, NLP, and production ML.

📱 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.