Decision boundaries
Where does logistic regression switch from "no" to "yes"? Exactly where w·x + b = 0. See that boundary as a line on a 2-D plane, and bend it into a circle with polynomial features.

In this lesson you will
- Show that the 0.5 threshold is the same as the condition w·x + b ≥ 0
- Draw the decision boundary of a two-feature model as a straight line
- Use polynomial features to get curved boundaries such as a circle
- Turn predicted probabilities into class predictions in NumPy
Logistic regression gives a probability. To make a decision we threshold it: predict when . In this lesson we ask a geometric question: which inputs land on each side? The dividing line between them is the decision boundary, and seeing it is the best way to understand what a classifier can and can’t do.
The threshold in terms of z
Recall that with , and that the sigmoid crosses 0.5 exactly at . Since only ever rises, it follows that
So the model predicts 1 whenever the linear part is zero or positive, and 0 when it’s negative. The sigmoid doesn’t move the boundary at all; it only turns distance from the boundary into confidence. The decision boundary is the set of points where
With one feature, that’s a single point, (the 4 cm from the last lesson). With two features it’s a line.
Two features, one line
A university admits students using two exam scores, and , both out of 10. Suppose the model is with , and . The boundary is
a straight diagonal line. A student with scores (7, 6) has , so they’re predicted “admitted”; one with (3, 4) has , so “not admitted”. The further a point is from the line, the larger and the more confident the prediction: (9, 9) gives and .
Each point is a student with two exam scores. Filled circles were admitted, and hollow squares were not.
The shading shows the probability everywhere on the plane: deep on one side, deep on the other, and pale along the boundary where the model is unsure. Drag , and :
- Changing shifts the line without turning it.
- Changing the ratio of to turns it. With , only exam 1 matters and the line is vertical.
- Scaling all three by the same factor keeps the line in the same place but makes the shading sharper: same boundary, more confidence.
Raise the Threshold and the line moves towards the “admitted” corner: the model now needs more evidence before it says yes. Thresholds other than 0.5 matter when one kind of mistake costs more than the other, which Section 5 explores.
Curved boundaries from polynomial features
Now switch the dataset to Ring. Class 1 sits inside a circle and class 0 surrounds it. No straight line can separate them; the best one gets only about two thirds right.
In Section 2 you turned linear regression into a curve by adding polynomial features such as . The same trick works here. Give the model the extra features , and :
The boundary can now be a circle or an ellipse. For example, with , everything else 0 and , the boundary is , the unit circle. The model is still linear in its parameters, so everything you know about training it still applies; it just looks at richer features. Set Polynomial degree to 2 and press Run to let gradient descent find the circle (the next lessons explain exactly how it does that).
Higher degrees allow wigglier boundaries. That power comes with a danger, overfitting, which has its own lesson later in this section.
Predictions in NumPy
In code you rarely draw the boundary. You compute probabilities for many examples at once, then
compare with the threshold. With the examples stacked as the rows of a matrix X, X @ w gives
every in one go (Python for Data, section 1):
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
X = np.array([[7.0, 6.0], [3.0, 4.0], [9.0, 9.0], [5.0, 5.0]]) # exam 1, exam 2
w = np.array([1.0, 1.0])
b = -10.0
z = X @ w + b
p = sigmoid(z)
print("z: ", z)
print("probability:", p.round(4))
print("prediction: ", (p >= 0.5).astype(int))Notice the student at exactly (5, 5): , probability 0.5, right on the boundary. By our convention () they’re predicted 1.
Exercise · Python
From probabilities to predictions
Solved ✓Complete predict(X, w, b, threshold=0.5). X has one example per row, w is the weight vector and b the bias. Compute the probability for every row, then return an array of integers: 1 where threshold, 0 elsewhere. sigmoid is provided.
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
def predict(X, w, b, threshold=0.5):
# 1. probabilities for every row of X
# 2. compare with the threshold, return 0/1 integers
return None # replace this line
X = np.array([[7.0, 6.0], [3.0, 4.0], [5.0, 5.0]])
print(predict(X, np.array([1.0, 1.0]), -10.0)) # expect [1 0 1]
Check yourself
Self-check · 4 questions