🌙 30-Day AI Ramadan Series  ·  Day 5 of 30
Deep Dive · Feb 23, 2026 · 14 min read · ML Models

Logistic Regression:
Teaching a Line to Think in Probabilities

One small mathematical trick — the sigmoid function — transforms a line into a probability machine. This 70-year-old algorithm still runs in production at every major tech company.

← Back to Blog ☰ Categories

A doctor looks at a patient's blood test results.
Cholesterol: 240. Blood pressure: 150/95. Age: 58. Smoker: yes.
She doesn't say: "Your heart disease score is 3.7."
She says: "There's an 80% chance you'll have a cardiac event in the next 10 years."

That's not linear regression. That's logistic regression.

01 — The Problem With Using Linear Regression for Classification

Suppose you want to predict: will this email be spam (1) or not spam (0)? You could try linear regression. The problem: linear regression outputs any number — it might predict 2.3 for a very spammy email, or -0.8 for a clean one. These are not probabilities. They don't even make sense as outputs for a yes/no question.

We need a model that outputs a number between 0 and 1 — interpretable as a probability. Logistic regression does exactly this by wrapping the linear model inside one clever function.

🌡️ Analogy

Think of a dimmer switch. Linear regression is a regular switch that can go from -100 to +100. You need something that, no matter how extreme the input, always outputs between 0 and 1. The sigmoid function is that dimmer — it squishes any input into the range (0, 1), smoothly, without discontinuity.

02 — The Sigmoid Function

The sigmoid (also written σ, the Greek letter "sigma") takes any real number and squashes it into the range (0, 1). The formula is:

σ(z) = 1 / (1 + e−z)

e is Euler's number — approximately 2.718, the base of natural logarithms. You don't need to memorize it. What matters is the behavior: as z grows very large, e−z shrinks to zero and σ(z) approaches 1. As z becomes very negative, e−z grows enormous and σ(z) approaches 0. At exactly z = 0, σ(0) = 0.5.

z = −5
σ(−5) ≈ 0.007 — the model is very confident this is class 0 (≈ 0.7% probability of class 1)
z = −1
σ(−1) ≈ 0.27 — leans toward class 0, but not confident (27% chance of class 1)
z = 0
σ(0) = 0.50 — the model is completely uncertain. This is the decision boundary.
z = +1
σ(+1) ≈ 0.73 — leans toward class 1 (73% probability)
z = +5
σ(+5) ≈ 0.993 — very confident this is class 1 (99.3% probability)

The full logistic regression model first computes the logit — the raw linear combination:

z = w1x1 + w2x2 + ... + wnxn + b

Then applies sigmoid to get the probability: p = σ(z). That probability is the final output — the model's confidence that the input belongs to class 1.

🔢 Worked example

Suppose a trained model learns w = 2.1 and b = −7.3 for tumor size. A patient has tumor size x = 3.8cm:

z = 2.1 × 3.8 − 7.3 = 7.98 − 7.3 = 0.68
p = σ(0.68) = 1 / (1 + e−0.68) ≈ 0.664

The model outputs 66.4% — meaning it believes there is a 66.4% probability that this tumor is malignant. Since 0.664 > 0.5, it predicts class 1 (malignant).

03 — The Decision Boundary

Once the model outputs a probability, we need a rule to make a final yes/no decision. The default: predict class 1 if p ≥ 0.5, class 0 if p < 0.5. The decision boundary is the precise line in input space where p = exactly 0.5 — the dividing line between predictions.

Since p = 0.5 when σ(z) = 0.5, and σ(z) = 0.5 when z = 0, the decision boundary is simply the set of inputs where w1x1 + ... + b = 0. That's a linear equation — which means the boundary is always a straight line in 2D, a flat plane in 3D, and a hyperplane in higher dimensions.

⚠️ The key limitation

If your two classes can't be separated by a straight line — if they're arranged in circles, spirals, or overlapping blobs — logistic regression will always draw a straight boundary and do its best, but it will never perfectly separate them. You can see this happening when training accuracy plateaus at a value clearly below 100% even with many epochs.

Fixes: Add polynomial features (x², x₁·x₂) to your input — this curves the boundary in the original space. Or switch to a non-linear model like a decision tree, SVM with a radial kernel, or a neural network.

🎯 Threshold tuning

The 0.5 threshold is not sacred. In fraud detection, you might lower it to 0.3 — catching more real fraud at the cost of more false alarms. In medical screening, you might lower it further to ensure almost no cases are missed, accepting a high false positive rate. The model gives you the probability; you choose where to draw the line based on the real-world cost of each type of mistake.

04 — How It Trains: Log-Loss (Cross-Entropy)

Logistic regression is trained with cross-entropy loss, also called log-loss. For a single example with true label y (either 0 or 1) and predicted probability p, the loss is:

Loss = −[ y · log(p) + (1 − y) · log(1 − p) ]

Let's unpack this. The formula has two branches — only one activates per example:

When y = 1 (true label is positive)
Loss = −log(p)

p = 0.99 → loss ≈ 0.01  ✓
tiny — model was confident and correct

p = 0.50 → loss ≈ 0.69  △
uncertain — moderate penalty

p = 0.01 → loss ≈ 4.60  ✗
enormous — model was confident and completely wrong
When y = 0 (true label is negative)
Loss = −log(1 − p)

p = 0.01 → loss ≈ 0.01  ✓
tiny — model was confident and correct

p = 0.50 → loss ≈ 0.69  △
uncertain — moderate penalty

p = 0.99 → loss ≈ 4.60  ✗
enormous — high confidence in the wrong direction is catastrophic

The reason we use logarithm rather than a simpler function: log grows very steeply near zero. A confident wrong prediction (p ≈ 0 when y = 1) creates a massive loss — and therefore a large gradient — driving the model to correct the mistake forcefully. MSE near the same point would give a loss of only ~1.0, providing a weak gradient signal. Cross-entropy makes training much faster and more stable for classification.

1
Compute the logit. z = w·x + b for each training example. This is the raw linear score — unconstrained, can be any real number.
The logit is also called the "log-odds" — the logarithm of the ratio of probability of class 1 to probability of class 0. You don't need this interpretation to use the model, but it's why the name "logistic" stuck.
2
Apply sigmoid. p = σ(z). The logit is squashed into (0, 1). This is now a probability.
3
Compute cross-entropy loss. Compare each predicted probability to its true label. Average across all training examples to get one loss number.
4
Gradient descent. Compute how each weight contributes to the loss, then nudge every weight in the direction that reduces it. Repeat thousands of times until the loss converges.

05 — From Scratch + sklearn

The from-scratch version makes every step explicit — sigmoid, cross-entropy gradient, and weight update. The sklearn version does the same thing with one line, using a more robust numerical solver internally.

import numpy as np

# Sigmoid: squashes any number into (0, 1)
def sigmoid(z): return 1 / (1 + np.exp(-z))

# Toy binary dataset: tumor size (cm) → malignant? (0=no, 1=yes)
X = np.array([1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0])
y = np.array([  0,   0,   0,   0,   1,   1,   1,   1])

# ── From scratch: gradient descent on cross-entropy loss ─────────────
w, b, lr = 0.0, 0.0, 0.1
for _ in range(3000):
    p  = sigmoid(w * X + b)          # predicted probabilities
    w -= lr * np.mean((p - y) * X)   # gradient of cross-entropy w.r.t. w
    b -= lr * np.mean(p - y)         # gradient w.r.t. b

print(f"Learned: w={w:.2f}, b={b:.2f}")
prob_scratch = sigmoid(w * 3.8 + b)
print(f"P(malignant | size=3.8cm) = {prob_scratch:.1%}")

# ── sklearn equivalent ────────────────────────────────────────────────
from sklearn.linear_model import LogisticRegression
import warnings; warnings.filterwarnings('ignore')
clf = LogisticRegression().fit(X.reshape(-1, 1), y)
prob_sklearn = clf.predict_proba([[3.8]])[0, 1]
print(f"sklearn  P(malignant | size=3.8cm) = {prob_sklearn:.1%}")
print(f"sklearn  Decision for 3.8cm: {'Malignant' if prob_sklearn >= 0.5 else 'Benign'}")
→ output
Learned: w=2.97, b=−9.57 P(malignant | size=3.8cm) = 87.2% sklearn P(malignant | size=3.8cm) = 88.4% sklearn Decision for 3.8cm: Malignant
💡 Reading the output

w = 2.97 — each additional centimetre of tumor size increases the logit by 2.97. Because this feeds into a sigmoid, the effect on probability is non-linear: it matters most near the decision boundary (z ≈ 0), and has diminishing impact far from it.

b = −9.57 — the baseline logit with zero size. A very negative number, which makes sense: a tumor of size 0cm should have near-zero malignancy probability.

87–88% — the small difference between scratch and sklearn is normal. sklearn uses a more numerically robust solver (LBFGS), not plain gradient descent. Both are correct.

06 — Regularization & When to Use It

Like linear regression, logistic regression can overfit when you have many features and limited data. Regularization adds a penalty for large weights, keeping the model simpler. sklearn's LogisticRegression() applies L2 regularization by default — controlled by the C parameter.

C parameter (inverse of strength)
Small C (e.g. 0.01) = strong regularization. The model is simpler and less likely to overfit, but may underfit. Large C (e.g. 100) = weak regularization. The model fits training data more closely, but risks overfitting. Default C=1 is a reasonable middle ground.
L2 / Ridge (penalty='l2')
Shrinks all weights toward zero proportionally. No weight ever reaches exactly zero — all features stay in the model. Good default when you think most features are at least somewhat useful.
L1 / Lasso (penalty='l1')
Can drive individual weights to exactly zero — effectively removing those features. Performs automatic feature selection. Ideal for high-dimensional data like text (thousands of word features) where most are irrelevant.
🔗 Connection to Modern AI

The final layer of BERT, GPT, and most classification neural networks is a logistic regression head — a linear layer followed by sigmoid (for binary) or softmax (for multi-class). When you fine-tune a pretrained model for sentiment analysis, you are essentially training a logistic regression on top of the model's learned representations. The 70-year-old algorithm is the last piece of the most modern architectures.

07 — A Thought to Sit With

💬 For You to Consider

Logistic regression outputs a probability — say, 73% chance of fraud. But the final decision (flag or don't flag) requires a threshold, typically 50%. Lowering it to 30% catches more real fraud — but also flags more legitimate transactions, frustrating honest customers.

Who should decide where that threshold sits — the data scientist, the business, or the regulator? And whose interests might conflict when each makes that choice?

08 — Coming Up Next

Tomorrow — Day 6: K-Nearest Neighbors. We abandon equations entirely. KNN makes predictions by asking "what do my closest neighbors predict?" — and in doing so, teaches something profound about the nature of similarity and distance in machine learning.

09 — Go Deeper

▶ StatQuest: Logistic Regression, Clearly Explained
YouTube · 19 min · The clearest visual explanation of odds, log-odds, and why sigmoid is the natural choice. Watch this directly after reading.

▶ Kaggle: Intro to Machine Learning
Free interactive course · Apply logistic regression to real classification datasets in your browser. The fastest way to go from reading to hands-on practice.

🧠 Check Your Understanding
1. Why can't we just use linear regression for binary classification?
Linear regression outputs unbounded values — it might predict 2.3 for a strong positive example or −0.8 for a negative one. These have no valid probabilistic interpretation. We need outputs that stay between 0 and 1. Additionally, MSE loss on binary targets provides weak gradient signals — cross-entropy is far more effective because it heavily penalizes confident wrong predictions. Logistic regression solves both problems: sigmoid constrains the output, and log-loss gives the right gradient behavior.
2. What does σ(0) equal, and what does that mean for the model's prediction?
σ(0) = 0.5 exactly. When the logit z = 0, the sigmoid outputs 0.5, meaning the model has zero confidence in either class. This is precisely the decision boundary — the set of all input combinations that produce z = 0 forms the line (or hyperplane) dividing the two predicted classes. Any input with z > 0 is predicted class 1; any with z < 0 is predicted class 0.
3. True label y = 1. The model outputs p = 0.02. What does the cross-entropy loss look like — and why does this matter?
Loss = −log(0.02) ≈ 3.91. The model was nearly certain the answer was class 0 (only 2% probability of class 1), but was wrong. The large loss creates a large gradient, forcing a strong weight correction. Compare this to MSE: (1−0.02)² ≈ 0.96 — a much weaker signal. This is the key advantage of cross-entropy for classification: confident mistakes generate enormous corrective pressure, while small mistakes are penalized proportionally less.
4. What shape is the decision boundary of a logistic regression model, and why?
Always linear — a straight line in 2D, a flat plane in 3D, a hyperplane in higher dimensions. The boundary occurs where σ(z) = 0.5, which means z = 0. Since z = w·x + b is a linear function, the set of points where z = 0 is itself a linear surface. If the true class boundary is curved, logistic regression cannot represent it. Solutions: add polynomial features to curve the boundary in the original space, or switch to a non-linear model.
5. In sklearn's LogisticRegression, what does C=0.01 versus C=100 do?
C is the inverse of regularization strength. C=0.01 means strong regularization — weights are heavily penalized for being large, the model stays simple, and overfitting is reduced at the potential cost of underfitting. C=100 means weak regularization — weights can grow large, the model fits the training data very closely, but risks overfitting on new data. The default C=1 is a reasonable starting point; tune it using cross-validation if performance is unsatisfactory.
⚡ Quick Recap — Logistic Regression
  1. What it does — Predicts the probability that an input belongs to a binary class (yes/no, spam/ham, malignant/benign).
  2. The logit (z) — Raw linear score: w·x + b. Unconstrained — any real number.
  3. Sigmoid σ(z) — Squashes logit into (0, 1). σ(0) = 0.5. Large positive → near 1. Large negative → near 0.
  4. Decision boundary — Where z = 0 and σ(z) = 0.5. Always a straight line or hyperplane.
  5. Cross-entropy loss — −[y·log(p) + (1−y)·log(1−p)]. Penalizes confident wrong predictions enormously.
  6. Why not MSE? — Cross-entropy creates much stronger gradients for confident mistakes, making training faster and more stable.
  7. Threshold — Default 0.5, but adjustable to control the tradeoff between false positives and false negatives.
  8. Regularization — C controls strength (smaller = stronger). L1 removes irrelevant features; L2 shrinks all weights. L2 is the default.
  9. In modern AI — The classification head of BERT, GPT, and almost every neural network is a logistic regression (or its multi-class generalization, softmax).
🎯 Interview Questions
  1. Why can't we use linear regression for classification?
    Linear regression outputs unbounded values that don't represent valid probabilities. It also uses MSE, which produces weak gradient signals for binary targets — cross-entropy is far more effective because it heavily penalizes confident wrong predictions.
  2. What is the sigmoid function and why do we use it?
    σ(z) = 1/(1+e−z). It maps any real number to (0, 1), making the output a valid probability. It is smooth and differentiable everywhere, enabling gradient descent. It is also the natural inverse of the log-odds transformation.
  3. What loss function does logistic regression use and why not MSE?
    Cross-entropy: −[y·log(p) + (1−y)·log(1−p)]. It penalizes confident wrong predictions with a very large loss (log approaches infinity near 0), creating strong gradients. MSE gives approximately 1.0 loss for the same confident mistake — a much weaker corrective signal.
  4. What is the decision boundary in logistic regression?
    The set of inputs where σ(z) = 0.5, equivalently where z = 0. Since z = w·x + b is linear, the boundary is always a line, plane, or hyperplane. It cannot represent curved class boundaries without polynomial feature engineering.
  5. How does the C parameter in sklearn's LogisticRegression work?
    C is the inverse of regularization strength. Small C = strong regularization (simpler model, less overfitting). Large C = weak regularization (fits training data closely, risk of overfitting). Default C=1 is a good starting point.
📎 Attachments & Further Reading

No attachments for this topic yet.

#LogisticRegression#Classification#Sigmoid#CrossEntropy#MLModels#30DaysOfAI#Ramadan2026#sklearn
← Day 4 Linear Regression