Machine learning means finding patterns in data rather than writing rules by hand. In Python that mostly means scikit-learn, and a first model is about fifteen lines. This guide builds one end to end and explains what each step is for — particularly the train/test split, which is the part beginners most often get wrong and the part that decides whether your results mean anything.
What machine learning is doing#
Ordinary programming: you write the rules, the computer applies them. Machine learning: you supply examples with known answers, and the computer works out rules that fit them.
That is useful when the rules are too complex or too fuzzy to write down — recognising handwriting, flagging unusual transactions, predicting how long a delivery will take. It is the wrong tool when a rule would do. If “reject orders over 1000 pounds” solves your problem, write that.
Setting up#
python -m venv .venv
source .venv/bin/activate # .venv\Scripts\activate on Windows
pip install scikit-learn pandas matplotlib
Four libraries cover the basics: pandas for loading and cleaning data, NumPy for arrays (installed with the others), scikit-learn for models, and matplotlib for plots.
A complete first model#
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 data
data = load_iris()
X, y = data.data, data.target
# 2. Split it
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
# 3. Choose and train a model
model = RandomForestClassifier(n_estimators=100, random_state=42)
model.fit(X_train, y_train)
# 4. Predict on data it has never seen
predictions = model.predict(X_test)
# 5. Measure
print("Accuracy:", accuracy_score(y_test, predictions))
print(classification_report(y_test, predictions, target_names=data.target_names))
Those five steps are the shape of nearly every supervised learning task. Changing the model on line 3 is often the smallest part of the work.
What X and y mean#
X is the features — what you know. y is the target — what you want to predict. The convention is a capital X because it is a two-dimensional table, and a lowercase y because it is a single column.
print(X.shape) # (150, 4) - 150 examples, 4 measurements each
print(y.shape) # (150,) - one label per example
print(X[0], y[0]) # the first flower and its species
The split is the important part#
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
Eighty per cent to learn from, twenty per cent held back. The model never sees the test set during training, so its score on that set estimates how it will do on data it has genuinely never encountered.
Two arguments matter beyond the split itself. random_state makes the split reproducible, so your results do not change every run. stratify=y keeps the proportion of each class the same in both halves, which matters a great deal when one class is rare.
Reading the numbers#
precision recall f1-score support
setosa 1.00 1.00 1.00 10
versicolor 0.91 1.00 0.95 10
virginica 1.00 0.90 0.95 10
accuracy 0.97 30
- Accuracy — the share of predictions that were right. Misleading when classes are unbalanced.
- Precision — of the cases predicted as this class, how many really were. High precision means few false alarms.
- Recall — of the cases that really were this class, how many were found. High recall means few missed.
- F1 — a single number balancing the two.
Which one matters depends entirely on the cost of each mistake. For a medical screening test, missing a case is far worse than a false alarm, so recall dominates. For a spam filter it is the reverse.
Accuracy alone can be actively deceptive. If 99 per cent of transactions are legitimate, a model that always says “legitimate” is 99 per cent accurate and completely useless.
Working with your own data#
import pandas as pd
from sklearn.model_selection import train_test_split
df = pd.read_csv("customers.csv")
print(df.head())
print(df.info())
print(df.isna().sum()) # missing values per column
df = df.dropna(subset=["age", "spend"])
X = df[["age", "spend", "visits"]]
y = df["churned"]
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y
)
Realistically, most of the work is here — loading, inspecting, handling missing values and choosing features. Training the model is the short part.
Categorical data and scaling#
Models need numbers, and several models need those numbers on comparable scales. A pipeline keeps the preparation attached to the model so it cannot be applied inconsistently:
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
numeric = ["age", "spend"]
categorical = ["country"]
preprocess = ColumnTransformer([
("num", StandardScaler(), numeric),
("cat", OneHotEncoder(handle_unknown="ignore"), categorical),
])
model = Pipeline([
("prep", preprocess),
("clf", LogisticRegression(max_iter=1000)),
])
model.fit(X_train, y_train)
print(model.score(X_test, y_test))
Cross-validation#
A single split can be lucky. Cross-validation splits several ways and averages:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5)
print(scores)
print("mean:", scores.mean().round(3), "spread:", scores.std().round(3))
The spread matters as much as the mean. A model scoring 0.90 on every fold is more trustworthy than one averaging 0.90 while ranging from 0.70 to 0.99.
Choosing a model to start with#
| Task | Start with |
|---|---|
| Predict a category | RandomForestClassifier |
| Predict a number | RandomForestRegressor |
| Want an explainable model | LogisticRegression or LinearRegression |
| Group without labels | KMeans |
| Text | TfidfVectorizer plus LinearSVC |
Start with the simplest thing that could work and get a baseline number. A model you understand and can explain beats a slightly better one you cannot.
Questions people ask#
Do I need to know the maths?
Not to start. You do need to understand what the metrics mean and why the test set must stay unseen — those are judgement, not mathematics. Deeper theory becomes useful once you are choosing between models rather than using them.
How much data do I need?
More than you would like. A few hundred examples can work for a simple problem with a handful of clean features. Anything with many features or subtle patterns needs thousands.
What is overfitting?
When a model learns the noise in the training data rather than the pattern. The symptom is a large gap between training and test scores. Simpler models, more data and cross-validation all help.
Should I use deep learning?
Rarely, for tabular data. Gradient-boosted trees usually match or beat neural networks on spreadsheet-shaped problems with far less effort. Deep learning earns its place for images, audio and language.
Where to go next#
- Python and data science — pandas and NumPy, the step before this.
- Machine learning introduction — the concepts without the code.
- Python virtual environments — where to install these libraries.