Classical Machine Learning
Fit, validate, tune and fix regression, classification and clustering models with scikit-learn.
- Concepts and terms
- Tasks and commands
- Annotated code
- Diagrams
- Defaults and numbers
- Troubleshooting
- Questions and tips
Fit a model#
| Task | Code |
|---|---|
| L2 regularized regression | Ridge(alpha= |
| Classifier for rare positives | LogisticRegression(class_weight= |
| Random forest | RandomForestClassifier(n_estimators= |
| Kernel SVM | SVC(kernel= |
| Linear SVM for large data | LinearSVC(C= |
| k nearest neighbours | KNeighborsClassifier(n_neighbors= |
| K-Means clusters | KMeans(n_clusters= |
| Density clusters and noise | DBSCAN(eps= |
From Lesson 02.02, Lesson 02.17, Lesson 02.04, Lesson 02.05, Lesson 02.06, Lesson 02.07
Metrics#
| Metric | Formula and use |
|---|---|
| Accuracy | (TP + TN) / (TP + TN + FP + FN). Misleading on imbalanced classes |
| Precision | TP / (TP + FP). Use when false positives are costly |
| Recall | TP / (TP + FN). Use when false negatives are costly |
| F1 | 2 \cdot P \cdot R / (P + R). Harmonic mean of both |
| AUC-ROC | 0.5 is random, 1.0 is perfect. Threshold independent |
| R-squared | 1 - SS_{\text{res}} / SS_{\text{tot}}. Below 0 is worse than the mean |
From Lesson 02.09, Lesson 02.17
Key formulas#
- MSE
- \text{MSE} = \frac{1}{n} \sum (y_{\text{predicted}} - y_{\text{actual}})^2
- Normal equation
- w = (X^T X)^{-1} X^T y. Cost is O(n^3) in features.
- Ridge
- \text{Cost} = \text{MSE} + \lambda \sum w_i^2
- Log loss
- -\frac{1}{n} \sum \left( y \log(p) + (1-y) \log(1-p) \right), p = \sigma(wx + b)
- Gini
- \text{Gini}(S) = 1 - \sum_k p_k^2. 0 is a pure node.
- Soft margin SVM
- \min \frac{1}{2} \lVert w \rVert^2 + C \sum_i \max(0, 1 - y_i (w^T x_i + b))
- RBF kernel
- K(x, z) = \exp(-\gamma \lVert x - z \rVert^2)
- Error split
- \text{Bias}^2 + \text{Variance} + \text{Irreducible Noise}
From Lesson 02.02, Lesson 02.03, Lesson 02.04, Lesson 02.05, Lesson 02.10
Leak-free preprocessing#
Leaky: the scaler sees the test rows
X_scaled = scaler.fit_transform(X)Correct: fit on train, reuse on test
X_train_scaled = scaler.fit_transform(X_train)learn mean and stdX_test_scaled = scaler.transform(X_test)train statistics onlyBest: one Pipeline object for train and serve
pipe = Pipeline([ ("scaler", StandardScaler()), ("model", LogisticRegression()),])pipe.fit(X_train, y_train)fit_transform, then fitpredictions = pipe.predict(X_test)transform, then predictscores = cross_val_score(full_pipe, df, y, cv=5, scoring="accuracy")refit per foldValidate without leakage#
From Lesson 02.09, Lesson 02.13
Questions#
- Why not MSE for logistic regression?
- With a sigmoid it is non-convex. Log loss is convex.
- Why scale before an SVM?
- The margin depends on \lVert w \rVert.
- Why does L1 select features?
- It pushes some weights exactly to zero.
- Will more data fix high bias?
- No. Change the model.
- Why class weights over oversampling?
- Same in expectation, no duplicate rows.
From Lesson 02.03, Lesson 02.05, Lesson 02.10, Lesson 02.17, Lesson 02.09
Tips#
- Sweep the learning rate first. Fix the rest at defaults.
- Search learning rate and regularization on a log scale.
- Set n_estimators high and let early stopping decide.
- Use nested cross-validation for the final estimate.
- Add a was_this_missing column before you impute.
- Pick the threshold on the validation set, not the test set.
ColumnTransformer pipeline#
Tune hyperparameters#
param_dist = { "learning_rate": loguniform(1e-4, 0.5),log scale for rates "max_depth": randint(2, 10),integer range "n_estimators": randint(50, 500),}search = RandomizedSearchCV( GradientBoostingRegressor(), param_dist, n_iter=100, cv=5,100 samples, 5 folds each scoring="neg_mean_squared_error",negated, higher is better random_state=42, n_jobs=-1,all CPU cores)search.fit(X_train, y_train)print(search.best_params_, -search.best_score_)negate back to MSEFrom Lesson 02.12
Troubleshooting#
| Symptom | Cause | Fix |
|---|---|---|
| High train and test error | high bias | more features, complex model, less regularization |
| Low train error, high test error | high variance | more data, regularization, simpler model |
| Test error rises, train error falls | overfitting in progress | early stopping |
| CV score higher than production | scaler fit on full data | Pipeline with cross_val_score |
| Crash on a new category | encoder never saw the value | OneHotEncoder(handle_unknown= |
| 99% accuracy, no positives found | class imbalance | class weights, threshold tuning |
| SVM or KNN scores low | unscaled features | StandardScaler() first |
| Best value at the search edge | range too narrow | widen the search space |
From Lesson 02.10, Lesson 02.13, Lesson 02.17, Lesson 02.05, Lesson 02.12, Lesson 02.06
Starting values#
| Setting | Default | Note |
|---|---|---|
| Decision threshold | 0.5 | lower it for rare positives |
| CV folds K | 5 | 10 is also standard |
| Features per split, forest | sqrt(n_features) | n_features / 3 for regression |
| Trees in a forest | 100 | n_estimators in the lesson code |
| Boosting learning_rate | 0.1 | typical 0.01 to 0.3 |
| Boosting max_depth | 3 | lesson GradientBoosting class |
| Naive Bayes alpha | 1.0 | Laplace smoothing |
| Out of bag share | 36.8% | free validation set |
From Lesson 02.17, Lesson 02.09, Lesson 02.11, Lesson 02.04, Lesson 02.14
Abbreviations#
- AUC-ROC
- Area Under the Receiver Operating Characteristic curve.
- SMOTE
- synthetic minority samples by k-NN interpolation.
- GMM
- Gaussian Mixture Model. Soft clusters by Expectation-Maximization.
- RFE
- Recursive Feature Elimination. Train, rank, prune, repeat.