Start learning

Machine Learning Workflow

Lesson 48. About 8 minutes.

A machine learning project is more than a call to fit. It's a sequence: define the problem, get and explore the data, prepare it, pick a baseline, try models, tune, evaluate once on the test set, and then deploy and monitor.

Your Path Through This Lesson

0 of 5 done

By the End of This Lesson You Can
  • List the stages of a complete machine learning project.
  • Build one end-to-end project with a pipeline.
  • Avoid the most common mistakes, especially data leakage.

The Stages

# Stage Key questions
1 Define the problem What are we predicting? Classification or regression? What metric matters?
2 Get the data Where does it come from? Is it enough? Is it representative?
3 Split Set aside a test set first, before looking closely
4 Explore Distributions, missing values, outliers, correlations
5 Prepare Fill missing values, encode categories, scale
6 Baseline What score does a trivial model get?
7 Try models Compare a few with cross-validation
8 Tune GridSearchCV on the best candidates
9 Evaluate Score the final model once on the test set
10 Deploy and monitor Save the model, serve predictions, watch for drift

The loop isn't strictly one-way: exploring often sends you back to collect more data, and errors in evaluation send you back to preparation.

A Complete Example

The breast-cancer dataset: predict whether a tumour is malignant (0) or benign (1).

1–3. Define, Load, Split

Missing a malignant tumour is worse than a false alarm, so we'll watch recall for malignant as well as accuracy.

python
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

data = load_breast_cancer(as_frame=True)
X, y = data.data, data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)

print("train:", X_train.shape, "  test:", X_test.shape)
print("class balance in train:", np.bincount(y_train))
Output
train: (455, 30)   test: (114, 30)
class balance in train: [170 285]

4. Explore (Training Data Only)

python
print("missing values:", int(X_train.isna().sum().sum()))
print(X_train[["mean radius", "mean area", "mean smoothness"]].describe().loc[["mean", "std", "min", "max"]].round(2))
Output
missing values: 0
      mean radius  mean area  mean smoothness
mean        14.07     648.54             0.10
std          3.50     344.94             0.01
min          6.98     143.50             0.06
max         28.11    2499.00             0.14

No missing values, but very different scales (area in hundreds, smoothness around 0.1), so distance-based and linear models will need scaling.

5–6. Baseline

python
from sklearn.dummy import DummyClassifier
from sklearn.model_selection import cross_val_score

baseline = DummyClassifier(strategy="most_frequent")
print(f"baseline CV accuracy: {cross_val_score(baseline, X_train, y_train, cv=5).mean():.3f}")
Output
baseline CV accuracy: 0.626

Always predicting "benign" already scores about 63%. Any real model must beat that clearly.

7. Compare Models

Each candidate is a pipeline, so scaling is fitted inside each cross-validation fold:

python
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

candidates = {
    "logistic regression": make_pipeline(StandardScaler(), LogisticRegression(max_iter=5000)),
    "KNN": make_pipeline(StandardScaler(), KNeighborsClassifier()),
    "SVM (RBF)": make_pipeline(StandardScaler(), SVC()),
    "random forest": RandomForestClassifier(random_state=0),
}
for name, model in candidates.items():
    scores = cross_val_score(model, X_train, y_train, cv=5)
    print(f"{name:>19}: {scores.mean():.3f} ± {scores.std():.3f}")
Output
logistic regression: 0.980 ± 0.013
                KNN: 0.967 ± 0.021
          SVM (RBF): 0.971 ± 0.018
      random forest: 0.956 ± 0.016

8. Tune the Best Candidates

python
from sklearn.model_selection import GridSearchCV

pipe = make_pipeline(StandardScaler(), LogisticRegression(max_iter=5000))
search = GridSearchCV(pipe, {"logisticregression__C": [0.01, 0.1, 1, 10, 100]}, cv=5).fit(X_train, y_train)
print("best C:", search.best_params_["logisticregression__C"])
print(f"best CV accuracy: {search.best_score_:.3f}")
Output
best C: 0.1
best CV accuracy: 0.980

9. Evaluate Once on the Test Set

python
from sklearn.metrics import classification_report, confusion_matrix

final = search.best_estimator_
pred = final.predict(X_test)
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred, target_names=["malignant", "benign"], digits=3))
Output
[[40  2]
 [ 1 71]]
              precision    recall  f1-score   support

   malignant      0.976     0.952     0.964        42
      benign      0.973     0.986     0.979        72

    accuracy                          0.974       114
   macro avg      0.974     0.969     0.972       114
weighted avg      0.974     0.974     0.974       114

The confusion matrix shows exactly which mistakes remain. If missed malignant tumours are too many, lower the decision threshold for "benign" rather than retuning against the test set.

10. Save the Model

python
import joblib

joblib.dump(final, "cancer_model.joblib")       # save the whole pipeline
model = joblib.load("cancer_model.joblib")      # later, in the app
model.predict(new_patients)

Because the scaler lives inside the pipeline, the saved file contains everything needed to go from raw measurements to a prediction.

Common Mistakes

Mistake Why it hurts Fix
Data leakage: scaling, filling or selecting features on all data before splitting Test information sneaks into training; scores look better than reality Split first; put every preparation step in a pipeline
Tuning against the test set The test score is no longer an honest estimate Tune with cross-validation; touch the test set once
No baseline You can't tell whether 90% is good Always compare with DummyClassifier / DummyRegressor
Wrong metric Accuracy hides failures on rare classes Choose the metric from the problem (recall, F1, MAE, …)
Ignoring drift The world changes after deployment Monitor live inputs and accuracy; retrain regularly
Try It Yourself
  1. Add XGBClassifier and a tuned random forest to the comparison. Does either beat logistic regression?
  2. Compute the recall for malignant tumours when you predict malignant whenever final.predict_proba(X_test)[:, 0] > 0.3.
The Key Idea

Split first, explore and prepare inside pipelines, beat a baseline, compare and tune with cross-validation, and use the test set only once at the end.

Summary

  • Problem → data → split → explore → prepare → baseline → models → tune → test once → deploy and monitor.
  • Pipelines keep preparation inside cross-validation and make saving the model easy.
  • Beat a baseline, choose the right metric, and never tune on the test set.
  • You've finished the Machine Learning course. Next, the Deep Learning course takes these ideas into neural networks.