Logistic Regression: From Linear Scores to Probabilities
Despite the name, this is a classification algorithm — the one that actually solves the pass/fail problem linear regression couldn't.
Beginner
the problem: back to pass/fail
Linear Regression left off with a specific complaint:
reusing a straight line for the CI pass/fail problem produces an unbounded score that a single
outlier diff can drag around, with no natural floor or ceiling to make it behave like a
probability. Logistic regression is a small, deliberate fix to exactly that gap — take the
same weighted-sum score linear regression already computes, and pass it through a function
that squashes it into the range (0, 1), so the output can actually be
interpreted as "probability this run fails."
squashing a line into a probability: the sigmoid
The sigmoid function takes any real number and maps it into
(0, 1):
sigmoid(z) = 1 / (1 + e^(-z))
sigmoid(-10) -> 0.00005 # very negative input -> probability near 0
sigmoid(0) -> 0.5 # exactly zero -> perfectly undecided
sigmoid(10) -> 0.99995 # very positive input -> probability near 1
Large negative inputs get squashed toward 0, large positive inputs toward 1, and the
function is smooth and symmetric around z = 0, where it outputs exactly 0.5.
That's the whole mechanism — nothing about the underlying linear score changes; only what's
done with it after does.
the model: linear regression, then squash
Logistic regression computes the exact same weighted sum as linear regression, then feeds
it through sigmoid:
z = w1 * lines_changed + w2 * files_changed + w3 * touches_slow_suite + b
p_fail = sigmoid(z) # a number strictly between 0 and 1
# turn the probability into a hard yes/no with a threshold
prediction = "fail" if p_fail > 0.5 else "pass"
The parameters being trained — w1, w2, w3, b — are the same kind of numbers
as in linear regression, and training is still "search for the values that make predictions
match reality as closely as possible." What changes is what "closely" means, covered below.
Because sigmoid(z) = 0.5 exactly when z = 0, the 0.5 threshold
on the probability corresponds to a very simple condition on the underlying linear score:
w·x + b = 0. With two features that's a line splitting the feature plane
in half; with more features it's a flat hyperplane. Everything on one side of it gets
classified "fail," everything on the other "pass" — which is why logistic regression is
called a linear classifier: the boundary between classes is always flat,
never curved, no matter how the sigmoid bends the probability itself.
why squared error breaks down here
It's tempting to train this exactly like linear regression — minimize mean squared error
between the predicted probability and the actual 0/1 label. The problem is deeper than "it
works less well": once MSE is combined with a sigmoid squashed into the mix, the resulting
cost surface stops being convex. A convex cost function has one clean bowl-shaped minimum,
which is exactly the shape gradient descent is good at finding; a non-convex surface can have
multiple local dips, and gradient descent can get stuck in one of them without ever finding
the actual best fit. Linear regression's MSE is convex because the model itself is linear;
squashing it through sigmoid first breaks that property.
the fix: log loss (binary cross-entropy)
Logistic regression uses a different per-example loss instead — designed specifically to
stay convex through the sigmoid and to reflect what actually matters for a probability: how
far off it was, on a scale that punishes confident-and-wrong far more than
uncertain-and-wrong.
# actual is 1 or 0; p_fail is the model's predicted probability of "fail"
loss = -log(p_fail) if actual == 1 # penalize a low probability when the true answer was "fail"
loss = -log(1 - p_fail) if actual == 0 # penalize a high probability when the true answer was "pass"
Read what happens at the extremes: if the true label is "fail" and the model predicted
p_fail = 0.99, -log(0.99) is a tiny loss — barely any penalty for
being confidently right. If it predicted p_fail = 0.01 for an actual failure,
-log(0.01) is a huge loss — a steep penalty for being confidently wrong. That
asymmetric, unbounded penalty for confident mistakes is exactly what pushes training to
separate the classes cleanly rather than hedge toward 0.5 everywhere. Averaged over every
training example, this per-example loss becomes the cost function that
gradient descent minimizes — the same gradient descent covered in depth later in this track,
just applied to a different cost function than linear regression's.
beyond two classes: softmax, briefly
Sigmoid handles exactly two outcomes. If the CI problem were "predict which of five
failure categories this run belongs to" instead of a binary pass/fail, the natural extension
is softmax: it takes a raw score for every class and turns the whole set
into a probability distribution that sums to 1 across all classes, rather than a single
independent 0-to-1 number per class. Sigmoid is the special case of softmax with exactly two
classes. This gets picked up again once neural network output layers are covered later in
this site's Deep Learning track.
from sklearn.linear_model import LogisticRegression| https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html | despite the name, this is scikit-learn's classifier -- fits via log loss, not squared error |'logr_sk1'
model.predict_proba(X_test)| | returns the actual probabilities -- predict() alone only gives you the thresholded 0/1 class, throwing away information you often want |'logr_sk2'
LogisticRegression(class_weight='balanced')| | the same class-imbalance fix introduced in the ML pipeline page -- most CI runs pass, so an unweighted model can default toward always predicting "pass" |'logr_sk3'
0.5 is a default threshold, not a law of nature. If a missed failure (predicting "pass"
when the run actually fails, wasting a slow test cycle) is more costly than a false alarm
(predicting "fail" and running extra checks unnecessarily), lowering the threshold to, say,
0.3 trades some false alarms for fewer missed failures. Choosing that threshold is a business
decision layered on top of the model's raw probability output, not something the model
decides for you.
Linear Regression — the regression counterpart this
page builds directly on.
Decision Trees — a completely different way to draw a
decision boundary, no weighted sum involved.
The ML Pipeline — where model selection (stage 4) fits into
the bigger picture.