Skip to main content
Machine Learning · lesson 3 of 11
Machine Learning beginner Lesson 3 of 11

Introduction to Machine Learning Models

Build, train, and evaluate your first classification model using Scikit-Learn.

By SkillByExample · Updated

Machine learning focuses on algorithms that learn patterns from datasets. In this tutorial, we will build a classification model to predict iris species using scikit-learn.

Environment Setup

Install the required scientific packages:

pip install scikit-learn numpy pandas

Model Training Lifecycle

The machine learning lifecycle consists of:

  1. Loading and cleaning data.
  2. Splitting into training and test datasets.
  3. Defining and training the model estimator.
  4. Evaluating metrics.
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report

# 1. Load Dataset
raw_data = load_iris()
X = pd.DataFrame(raw_data.data, columns=raw_data.feature_names)
y = raw_data.target

# 2. Split Data (80% Train, 20% Test)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 3. Initialize and Train Model
classifier = RandomForestClassifier(n_estimators=100, random_state=42)
classifier.fit(X_train, y_train)

# 4. Predict and Evaluate
predictions = classifier.predict(X_test)
accuracy = accuracy_score(y_test, predictions)

print(f"Model Accuracy: {accuracy:.4f}")
print("\nClassification Report:")
print(classification_report(y_test, predictions, target_names=raw_data.target_names))
$ python ml_lifecycle.py
Model Accuracy: 0.9000

Classification Report:
              precision    recall  f1-score   support

      setosa       1.00      1.00      1.00        10
  versicolor       0.82      0.90      0.86        10
   virginica       0.89      0.80      0.84        10

    accuracy                           0.90        30
   macro avg       0.90      0.90      0.90        30
weighted avg       0.90      0.90      0.90        30

Setosa is linearly separable from the other two species, so the forest gets it perfect. The errors are all versicolor/virginica confusion — those two overlap in petal measurements, which is why precision and recall split unevenly between them instead of failing uniformly.

Tracking Parameters

In production environments, avoid running scripts blind. Use MLOps systems like MLflow to track parameters:

import mlflow

with mlflow.start_run():
    mlflow.log_param("n_estimators", 100)
    mlflow.log_metric("accuracy", accuracy)
    mlflow.sklearn.log_model(
        classifier, name="model", skops_trusted_types=["sklearn.tree._tree.Tree"]
    )
    print("Logged run:", mlflow.active_run().info.run_id)
$ python ml_mlflow.py
Logged run: 6606a35aedb64eed890f7bf2f63ee2bc

Your run ID will differ — MLflow generates a fresh one per run. As of MLflow 3.x, log_model serializes scikit-learn estimators with skops instead of pickle, and skops refuses to load tree-based models (RandomForest, GradientBoosting, decision trees) unless you name sklearn.tree._tree.Tree in skops_trusted_types — the flat node-index arrays those models store aren’t bounds-checked on load, so skops treats them as untrusted by default. Only pass that argument for models you created yourself.

Practice

  1. Change test_size from 0.2 to 0.4 and re-run. Does accuracy go up or down, and why might a smaller training set hurt a forest more than a linear model?

    Solution

    Accuracy typically drops a little (fewer training examples means less data per tree to split on), and the per-class report becomes noisier because each test class now has more than 10 samples, so a single misclassification swings the score less.

  2. Swap RandomForestClassifier for sklearn.linear_model.LogisticRegression (add max_iter=200) and compare classification_report output.

    Solution
    from sklearn.linear_model import LogisticRegression
    classifier = LogisticRegression(max_iter=200, random_state=42)

    On this dataset logistic regression scores similarly to the forest — iris is small and close to linearly separable, so the extra capacity of a forest isn’t needed.

  3. Log a second MLflow run with n_estimators=10 instead of 100 and compare the logged accuracy metric between runs using mlflow.search_runs().

    Solution
    import mlflow
    runs = mlflow.search_runs(order_by=["metrics.accuracy DESC"])
    print(runs[["run_id", "metrics.accuracy", "params.n_estimators"]])

    Fewer trees usually means a small accuracy drop, though on a dataset this small the gap can be within noise.

  4. Remove stratify=y from the train_test_split call and re-run several times. Why does the classification report vary more between runs now?

    Solution

    Without stratification, each split’s class proportions are random, so a small test set (30 rows) can end up with, say, 12 setosa and 6 virginica instead of an even 10/10/10 split — that imbalance shows up directly in per-class support and recall.