Machine Learning · Week 1
Foundational ML Models and Sklearn
Choose a model for a clearly defined task, compare it with a baseline, and evaluate it on observations it has not learned from. You will use scikit-learn's shared estimator interface to compare linear and nonlinear classifiers fairly.
Before you start: Week 0: feature/target separation, train/test splits, scaling, and pipelines.
- Define the task
- Build a baseline
- Compare with CV
- Evaluate once
1. Start with the output you need
Regression predicts a numeric quantity, such as duration. Classification predicts a label or class probabilities, such as whether an event occurs. Clustering groups observations without supervised target labels. A clustering label is not automatically a known class label.
Linear regression models a numeric target as a weighted sum plus a bias. Binary logistic regression instead maps a weighted sum through a sigmoid to estimate the probability of class 1. Despite its name, LogisticRegression is a classifier. A threshold turns its probability estimate into a class decision.
Linear regression: prediction = w · x + b
Logistic regression: P(y = 1 | x) = 1 / (1 + exp(-(w · x + b)))Documentation: Linear and logistic models
2. Know what each model can express
A model is a set of possible prediction rules plus a procedure for fitting one of them. Simpler rules may miss nonlinear structure; flexible rules may fit noise. Start with a small number of models whose assumptions you can explain. These are starting points, not a universal ranking.
| Model | Prediction rule | Useful controls |
|---|---|---|
| Linear / logistic regression | Weighted inputs; logistic adds a probability mapping | Regularization; feature scaling |
| k-nearest neighbors | Average or vote among nearby examples | Neighbor count; distance; scaling |
| Decision tree | A sequence of feature-based splits | Maximum depth; minimum leaf size |
| Random forest | Aggregate predictions from randomized trees | Tree count; depth; minimum leaf size |
One score, two prediction tasks.
Change the same weight and bias in a linear numeric predictor and a logistic probability predictor. These controls set parameters by hand; they do not fit a dataset.
At x = 1: p = 0.731; predicted class 1
Think it through: Does sigmoid make the 0.5 decision boundary nonlinear?
The sigmoid curve is nonlinear, but p = 0.5 occurs where the affine score is zero. With several raw input features that boundary is a hyperplane. Nonlinear engineered features can change the boundary in the original input space.
Documentation: Choosing an estimator
3. Use the estimator interface consistently
fit(X_train, y_train) learns from training examples. predict(X_new) returns labels or numeric predictions. Classifiers that implement predict_proba return one column per class, in classes_ order. That order must be checked before interpreting a probability column.
A DummyClassifier ignores the inputs and follows a simple rule, such as always choosing the most frequent training class. Beating that baseline is a minimum useful comparison. It can already achieve high accuracy when one class dominates. Each candidate's preprocessing belongs inside its pipeline.
Documentation: DummyClassifier
4. Compare models on the same validation folds
First reserve a test set. Then divide the remaining training data into folds. For each candidate and fold, fit on the other folds and score on the held-out fold. Reusing the same folds makes the comparisons easier to interpret. Pick the model using mean validation performance, refit it on all training data, and evaluate it on the reserved test set.
The fold standard deviation describes variation across those folds; it is not automatically a confidence interval. Training scores can reveal a large training/validation gap, but a good training score alone says little about generalization. Model selection uses validation scores, never the final test score.
Rotate validation. Keep the final test set reserved.
Twenty development rows form five illustrative folds. Four additional rows are reserved for final testing. Select which development block provides validation for this fit.
Repeat all five fits for every candidate using the same assignments. Each development row supplies validation once. Real splitting must also respect class balance, groups, or time when applicable.
Think it through: Does each fold reuse the same fitted scaler?
No. Each fit starts with a fresh pipeline. Its scaler and model learn only from that fold's training rows. After selection, refit the chosen pipeline on all development rows and evaluate the reserved test set.
Documentation: Cross-validation and model evaluation
5. Read errors as well as scores
For a chosen positive class, a true positive is a correctly detected positive; a false positive is a negative incorrectly flagged positive. A false negative is a missed positive. Precision asks how many positive predictions are correct. Recall asks how many actual positives were found.
Suppose TP=8, FP=2, FN=4, and TN=6. Precision is 8/10=0.80, recall is 8/12≈0.67, and accuracy is 14/20=0.70. Choose metrics according to the mistakes that matter. Balanced accuracy averages recall across classes. ROC AUC evaluates ranking from scores across thresholds; it is not the accuracy at a particular threshold.
| Metric | Definition or interpretation | Watch for |
|---|---|---|
| Accuracy | Correct predictions / all predictions | Dominant classes can hide missed minorities |
| Precision / recall | TP/(TP+FP) / TP/(TP+FN) | Specify the positive class and threshold |
| F1 | 2TP/(2TP+FP+FN) | Does not include true negatives |
| MAE / RMSE | Regression errors in target units | RMSE gives larger errors more influence |
Move the threshold. Watch the mistakes change.
These sixteen labeled validation examples have fixed illustrative scores. Moving the decision threshold changes predictions without retraining a model.
| Actual | Predicted 0 | Predicted 1 |
|---|---|---|
| 0 | TN = 5 | FP = 2 |
| 1 | FN = 3 | TP = 6 |
Precision = TP / (TP + FP). It is undefined when no rows are predicted positive; the display preserves that distinction.
Think it through: What changes when you raise the threshold?
For these fixed scores, fewer rows are predicted positive. True and false positives can only decrease, and recall cannot increase. Precision need not increase at every step. The ranking of scores is unchanged. Choose a threshold on validation data, not the final test set.
Documentation: Metrics and scoring
Complete example: Compare classifiers on two curved classes
The two-moons dataset has two numeric features and two curved classes. Compare a dummy baseline, logistic regression, a tree, and a random forest using five-fold cross-validation. Only the selected model sees the final test evaluation.
Install the packages in your Python environment, then download and run the script. The example creates its data locally.
python -m pip install numpy scikit-learn
python ml-week-1.pyDownload Python example ↓import numpy as np
from sklearn.base import clone
from sklearn.datasets import make_moons
from sklearn.dummy import DummyClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import (balanced_accuracy_score, confusion_matrix,
f1_score, roc_auc_score)
from sklearn.model_selection import (StratifiedKFold, cross_validate,
train_test_split)
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
X, y = make_moons(n_samples=1000, noise=0.25, random_state=7)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
folds = list(cv.split(X_train, y_train))
models = {
"dummy": DummyClassifier(strategy="most_frequent"),
"logistic": make_pipeline(StandardScaler(),
LogisticRegression(max_iter=1000)),
"tree": DecisionTreeClassifier(max_depth=4, random_state=42),
"forest": RandomForestClassifier(n_estimators=100,
min_samples_leaf=3,
random_state=42, n_jobs=1),
}
means = {}
for name, estimator in models.items():
scores = cross_validate(estimator, X_train, y_train, cv=folds,
scoring="balanced_accuracy",
return_train_score=True)
means[name] = scores["test_score"].mean()
# Here test_score means each CV validation fold, not X_test.
print(name, "train", round(scores["train_score"].mean(), 3),
"validation", round(means[name], 3),
"fold std", round(scores["test_score"].std(), 3))
winner_name = max(means, key=means.get)
winner = clone(models[winner_name]).fit(X_train, y_train)
prediction = winner.predict(X_test)
positive_column = np.flatnonzero(winner.classes_ == 1)[0]
probability = winner.predict_proba(X_test)[:, positive_column]
assert prediction.shape == y_test.shape
assert np.isfinite(probability).all()
print("Selected:", winner_name)
print("Test balanced accuracy:", balanced_accuracy_score(y_test, prediction))
print("Test F1:", f1_score(y_test, prediction))
print("Test ROC AUC:", roc_auc_score(y_test, probability))
print("Confusion matrix; rows=true, columns=predicted, classes=[0, 1]:")
print(confusion_matrix(y_test, prediction, labels=[0, 1]))
What to look for
- The dummy classifier's balanced accuracy is 0.5 when both classes are present.
- The selected candidate has the highest mean validation score among these choices, not a guaranteed advantage on every future dataset.
- The confusion matrix counts sum to the 200 test observations. The held-out evaluation happens after model selection.
Practice and completion checks
Use only cross-validation on X_train to compare tree depths 1, 4, and unrestricted. Record training and validation scores.
You are done when: You can explain the gap for each depth without choosing settings from X_test.
Calculate accuracy, precision, recall, and F1 by hand for TP=8, FP=2, FN=4, TN=6.
You are done when: You obtain 0.70, 0.80, approximately 0.667, and approximately 0.727, respectively.
Describe a regression version of the workflow with DummyRegressor and a numeric target.
You are done when: Your baseline uses training data, your comparison uses validation MAE or RMSE, and your test set remains reserved.
Check your understanding
Answer each question first, then expand it to compare your reasoning.
Is LogisticRegression a regression estimator?
In scikit-learn it is a classifier. It estimates class probabilities from a linear score; LinearRegression predicts a numeric target directly.
Why fit the selected model again after cross-validation?
Each fold trained on only part of the development data. Refitting learns one final model from all available training rows using the selected configuration.
Why can 99% accuracy be unhelpful?
If 99% of examples belong to one class, predicting that class for every row gets 99% accuracy while detecting none of the other class. Compare a baseline and inspect per-class errors.
Can a random forest always beat logistic regression?
No. Performance depends on the data, features, sample size, hyperparameters, and evaluation design. Compare candidates under the same validation procedure.