Build Your First ML Model with Scikit-Learn

AI Tutor Code··8 min read

Last updated: June 2026

In this tutorial you build a working machine learning classifier with scikit-learn, the standard Python library for classical ML. You will load a real dataset, train a model that learns to tell three flower species apart from their measurements, and score it honestly on data it has never seen. By the end you will have a classifier running locally that hits roughly 95 percent accuracy, and you will understand the five-step pattern that every scikit-learn project reuses.

That pattern is the whole point. Once you can run it once, you can swap the dataset and the model and run it again on a churn prediction, a price forecast, or a customer segmentation. The code barely changes.

What you need before starting

  • Python 3.9 or newer installed, with pip working in your terminal
  • Comfort with Python basics: variables, lists, functions, importing modules
  • A little Pandas (loading a DataFrame, selecting columns). If that is shaky, read Python for Adults first
  • A notebook environment (JupyterLab or VS Code with the Python extension)
  • 30 minutes and a willingness to run every block yourself, not just read

Step 1: Install scikit-learn and load a dataset

Install the library and its companions from your terminal. Scikit-learn ships several small datasets, so you can start learning the workflow immediately without hunting for a CSV or cleaning messy real-world data. That comes later, once the mechanics are second nature.

pip install scikit-learn pandas

Now load the classic iris dataset into a Pandas DataFrame. It holds 150 rows of flower measurements with a species label, which is exactly the shape of a small classification problem.

from sklearn.datasets import load_iris

data = load_iris(as_frame=True)
df = data.frame
print(df.shape)
print(df.head())

You should see (150, 5) printed, followed by the first five rows: four measurement columns plus a target column holding 0, 1, or 2 for the three species. The as_frame=True flag is what hands you a tidy DataFrame instead of raw NumPy arrays. The full schema lives in the official load_iris documentation.

Checkpoint: df.shape prints (150, 5) and df.head() shows four numeric columns and a target column.

Step 2: Separate features from the target

Machine learning models need a clear split between the inputs (the measurements) and the thing you are trying to predict (the species). By long convention these are named X for the features and y for the target.

X = df.drop(columns=["target"])
y = df["target"]

print(X.columns.tolist())
print(y.value_counts())

Dropping the target column from X is cleaner than listing every feature by hand, and it keeps working if the dataset gains columns later. The value_counts() call confirms the classes are balanced: 50 examples of each species. Balance matters more than beginners expect, and I will come back to it.

Checkpoint: X contains only the four measurement columns, and y.value_counts() shows 50 rows for each of classes 0, 1, and 2.

Step 3: Split into training and test sets

Here is the rule that separates real ML from self-deception: you never evaluate a model on the same data you trained it on. You hold back a chunk, train on the rest, and check performance on the held-back portion. Scikit-learn does this in one call.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=1, stratify=y
)

print(X_train.shape, X_test.shape)

This puts 75 percent of the rows in the training set and 25 percent in the test set. The random_state=1 makes the split reproducible, so you and I get the same rows. The stratify=y argument keeps the class balance identical across both sets, which the train_test_split documentation recommends for classification.

Checkpoint: the printout shows (112, 4) (38, 4), confirming 112 training rows and 38 test rows.

Step 4: Train a model

Now the actual learning. You pick a model, hand it the training features and labels, and call fit(). A decision tree is a strong first choice because it trains instantly and you can reason about how it decides.

from sklearn.tree import DecisionTreeClassifier

model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)

The fit() method is where the model studies the training data and builds its internal rules. Every scikit-learn model exposes this same fit() interface, so the muscle memory transfers to logistic regression, random forests, and the rest. I set max_depth=3 to keep the tree shallow, which is the simplest guard against the model memorizing noise. The DecisionTreeClassifier documentation lists the other knobs.

Checkpoint: model.fit(...) returns without error and printing model shows DecisionTreeClassifier(max_depth=3, random_state=42).

Step 5: Predict and score on the test set

Time to find out whether it actually learned anything. You ask the model to predict species for the test rows it has never seen, then compare those predictions against the true labels.

from sklearn.metrics import accuracy_score, classification_report

predictions = model.predict(X_test)
accuracy = accuracy_score(y_test, predictions)
print(f"Accuracy: {accuracy:.2%}")
print(classification_report(y_test, predictions))

You should see accuracy around 95 to 97 percent, plus a per-class breakdown of precision and recall. That report matters more than the single accuracy number, because it shows whether the model is strong on every species or quietly failing on one. Precision asks how many of the model's positive guesses were right; recall asks how many of the true positives it actually caught. A model can post high accuracy while missing an entire minority class, and only the per-class view exposes that.

Accuracy: 97.37%
              precision    recall  f1-score   support

           0       1.00      1.00      1.00        12
           1       0.93      1.00      0.96        13
           2       1.00      0.92      0.96        13

    accuracy                           0.97        38
   macro avg       0.98      0.97      0.97        38
weighted avg       0.98      0.97      0.97        38

You just built and validated a classifier. Those five steps (load, separate, split, fit, score) are the spine of nearly every scikit-learn project. The official Getting Started guide walks the same arc with different data, which is worth reading once the pattern feels familiar.

Checkpoint: the printout shows an accuracy above 90 percent and a classification_report table with three class rows.

Step 6: Swap in a different model with one line

Here is why scikit-learn is worth learning over hand-rolled ML. Every model shares the same fit and predict interface, so trading one for another is a single import and a single line. Replace the tree with a random forest, an ensemble of many trees that usually generalizes better.

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=200, random_state=42)
model.fit(X_train, y_train)
print(f"Accuracy: {model.score(X_test, y_test):.2%}")

Nothing else changed. Same X_train, same y_train, same scoring call. That consistency is the reason you learn one model and effectively get the rest for free.

Checkpoint: the random forest prints an accuracy in the same 95 to 100 percent range, proving the swap worked without touching your data pipeline.

Where this breaks

You skip the train/test split and trust the result. If you call fit() and score() on the same rows, the model can simply memorize them and report near-perfect accuracy that evaporates on real data. This is the single most common beginner mistake I see in sessions. Always split first, and treat the test set as untouchable until the final score.

Your classes are imbalanced and accuracy lies to you. Iris is perfectly balanced, but most real datasets are not. If 95 percent of your rows are one class, a model that always guesses that class scores 95 percent while learning nothing. Check y.value_counts() early, pass stratify=y to the split, and read the precision and recall in classification_report instead of trusting accuracy alone.

You forget to scale features for distance-based models. Decision trees and random forests do not care about feature scale, so this tutorial dodges the issue. The moment you switch to a model like KNN, SVM, or k-means, raw scale wrecks results, because a column measured in thousands drowns out a column measured in decimals. Wrap your model in a Pipeline with StandardScaler so scaling happens automatically and never leaks from test into train.

A single split gives you a noisy number. One 75/25 split is a single sample of how the model performs, and another random seed can move accuracy by several points. Before you trust a result, run cross_val_score(model, X, y, cv=5) to average performance across five folds. If the per-tutorial number and the cross-validated number disagree a lot, your dataset is small or your model is unstable.

What to build next

Swap the iris dataset for a CSV from your own work: load it with pd.read_csv, drop any rows with missing values, put the column you want to predict into y, and run the same five steps. Real data is messier than iris, so expect to spend most of your time cleaning before the model ever sees it. From there, the natural next move is honest evaluation across many models with cross-validation, which is where most of the real skill lives. The library covers regression and clustering with the same fit-and-predict shape, so the leap to those is small once this clicks. If you are weighing whether ML is the right direction at all, how long it takes to learn Python for work sets realistic expectations, and whether ChatGPT can teach you Python is worth reading before you lean on AI to learn this. If the credential question is what is stopping you, machine learning without a PhD answers it directly, and data science for career changers maps the wider route in.

If you want to build this with someone watching your screen and catching mistakes in real time, that is literally what my sessions are. Book a free Discovery Call and bring a dataset from your own job to it.

These tutorials come from the actual curriculum I teach 1-on-1. Every code block is tested before it ships.

Related articles

Keep reading on related topics.

Enjoyed this article?

You can master this and more with a dedicated 1-on-1 tutor.

Book a Free Discovery Call