A First Real Classifier: A Light Touch of scikit-learn

Data Science & ML Projects (Beginner)

Chapter 7 · A First Real Classifier: A Light Touch of scikit-learn

Six chapters, zero models — deliberately, per this course's own opening throughline. This one chapter is the exception: a small, honest taste of what ml1 covers in full depth, not a substitute for that course. Every shortcut this chapter takes is named explicitly, not smoothed over.

What We're Building

A classifier for the Iris dataset — the single most famous "hello world" of classification: predict which of three flower species a sample belongs to, from four simple measurements (sepal length, sepal width, petal length, petal width). It ships built directly into scikit-learn, needs zero cleaning, and is small enough to see the whole pipeline at once.

Step 1: Loading the Dataset

from sklearn.datasets import load_iris
import pandas as pd

iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["species"] = [iris.target_names[i] for i in iris.target]
print(df.head())

iris.data is a NumPy array of the four measurements; iris.target is the numeric species label for each row (0, 1, or 2). Building a DataFrame and mapping the numbers back to real species names makes the data readable the same way every prior chapter's own data has been.

Step 2: A Quick Look — Why This Dataset Works So Well

import seaborn as sns
import matplotlib.pyplot as plt

sns.scatterplot(
    data=df, x="petal length (cm)", y="petal width (cm)",
    hue="species", palette=["#15803D", "#EAB308", "#4ade80"],
)
plt.title("Petal Measurements by Species")
plt.savefig("iris_scatter.png")

Plotting just two of the four features already shows the three species separating into clearly distinct clusters — a genuine, visible reason this particular dataset became the classic teaching example: the classes are almost perfectly separable, letting even a simple model succeed clearly enough to see what's actually happening.

Step 3: Train/Test Split

from sklearn.model_selection import train_test_split

X = df[iris.feature_names]
y = df["species"]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
print(f"Training on {len(X_train)} rows, testing on {len(X_test)} rows.")

The full reasoning behind why a model needs to be evaluated on data it never saw during training is ml1-2's own material in full — used correctly here, not re-derived. random_state=42 just makes the split reproducible from one run to the next.

Step 4: Fitting a Simple Classifier

from sklearn.neighbors import KNeighborsClassifier

model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)
A deliberately different algorithm than ml1 covers
K-Nearest Neighbors classifies a new sample by looking at its n_neighbors closest points in the training data and taking a majority vote of their species — genuinely intuitive, no gradient descent or decision-tree splitting logic to explain. It's used here specifically because it's not logistic regression (ml1-5) or decision trees/random forests (ml1-7) — those get their own full, proper treatment in that course; this chapter isn't trying to preempt either one.

Step 5: Evaluating — The Single Simplest Metric

accuracy = model.score(X_test, y_test)
print(f"Accuracy: {accuracy:.2%}")
Accuracy alone is the simplified version
.score() here reports plain accuracy — the fraction of test predictions that were correct. It's genuinely the simplest possible metric, and genuinely not the full picture: ml1-6 covers precision, recall, F1, and the confusion matrix in depth, including exactly why accuracy alone can be misleading on imbalanced data. Iris happens to have equal numbers of each species, which is part of why plain accuracy is defensible here specifically — that won't be true of every dataset.

Step 6: Seeing the Predictions

predictions = model.predict(X_test)
results = X_test.copy()
results["actual"] = y_test.values
results["predicted"] = predictions
results["correct"] = results["actual"] == results["predicted"]

print(results[results["correct"] == False])   # the rows the model got wrong, if any

Looking directly at whichever rows the model got wrong (if any) is worth more than the single accuracy number alone — on this dataset, mistakes almost always happen between two of the three species that sit closest together in the Step 2 scatter plot, not randomly across all three, a small, concrete confirmation that the model is making genuinely sensible errors rather than arbitrary ones.

The Complete Classifier

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import pandas as pd

iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["species"] = [iris.target_names[i] for i in iris.target]

X = df[iris.feature_names]
y = df["species"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = KNeighborsClassifier(n_neighbors=5)
model.fit(X_train, y_train)

accuracy = model.score(X_test, y_test)
print(f"Accuracy: {accuracy:.2%}")

Built-in datasets

load_iris() ships with scikit-learn — no download, no cleaning needed.

train_test_split()

Used correctly here; ml1-2 covers the full reasoning behind it.

K-Nearest Neighbors

Classify by majority vote among the closest training points — no gradient descent.

Accuracy's own honest limits

The simplest metric, not the full picture — ml1-6 covers precision/recall/F1.

Extend This Project

Try these on your own:

  • Change n_neighbors to 1 and to 15 — how does accuracy change, and why might too few or too many neighbors both cause problems?
  • Once you've taken ml1, come back and fit a LogisticRegression or DecisionTreeClassifier on this exact same data and compare its accuracy to KNN's own.
  • Use only two features (say, petal length and width) instead of all four, and see how much accuracy actually drops.
  • Try the same pipeline on scikit-learn's other built-in dataset, load_wine(), with no other changes — does it still work this cleanly?

What's Next

Chapter 8: Capstone — Your Own Dataset, Start to Finish — no fixed dataset this time: your own choice, taken through the complete collect-clean-explore-visualize-model pipeline this course has built one piece at a time.

Chapter 7 Quick Reference

  • This course's own single, deliberately light touch of ml1 — a taste, not a substitute for that course's own full depth
  • Iris: built into scikit-learn, needs no cleaning, chosen specifically to keep the focus on the modeling pipeline itself
  • K-Nearest Neighbors used deliberately instead of logistic regression (ml1-5) or decision trees (ml1-7), so as not to preempt either
  • train_test_split() used correctly, not re-derived — ml1-2 covers the full reasoning
  • Plain accuracy reported honestly as the simplest metric, not the full evaluation picture ml1-6 covers