The box you have been trusting
You have fit this model at least four times across the courses - and never once asked what the numbers inside it mean. Fair: the workflow had to come first. But logistic regression is the single most-deployed classifier in industry precisely because its insides are readable - every coefficient is a claim about the world that you can state, check, and challenge. A model you can read is a model your stakeholders can trust, and today it becomes yours.
From line to probability 7 min live
Under the hood, logistic regression is session 2's model wearing a disguise. It computes the same weighted sum - z = w·x + b - a plain score that can be any number from minus infinity to plus infinity. Then one function, the sigmoid, squashes that score into (0, 1) so it can be read as a probability. Big positive z, probability near 1. Big negative z, near 0. z exactly 0, probability exactly 0.5 - and that is where the model changes its mind.
LiveThe sigmoid - what it does and why it is the right squash3 min▶
sigma(z) = 1 / (1 + e^-z). Three properties earn it the job. It is monotonic: a higher score always means a higher probability, so the linear ranking survives the squash. It is saturating: past z of about plus or minus 4 it flattens near 1 or 0, so absurd scores cannot produce probabilities above 1 or below 0. And it is symmetric around z = 0: sigma(0) = 0.5 exactly, which is what makes "score positive or negative" and "probability above or below a half" the same question.
So the model is two moving parts, not one mysterious blob: a linear scorer (all of session 2's machinery - weights, features, an intercept) and a fixed, parameter-free squash. Everything the model learns lives in the line. The sigmoid never changes.
LiveThe decision boundary is a line - see it on real Lumen data4 min▶
Where does the model flip from "no" to "convert"? Where p = 0.5, which is where z = 0, which is the equation w·x + b = 0 - and in feature space that is a straight line (a flat plane in more dimensions). This is session 1's boundary explorer coming home: of the four boundary signatures you met, logistic regression owns the calm straight seam.
Same explorer, now locked to logistic on the real sample - 2 features (spend x pages, standardized), balanced converters vs non-converters. Notice how the seam stays a straight, unbothered line at ~59% test accuracy: two features of real checkout data carry a weak, honest signal. Real data whispers.
Odds, log-odds, and the coefficient ladder 9 min live
To read the coefficients you need one ladder with three rungs. Probability: the chance of converting, lives in (0, 1). Odds: p / (1 - p), the ratio of converting to not converting, lives in (0, infinity). Log-odds: ln(odds), lives on the whole number line - and this is the rung where logistic regression is literally linear: z IS the log-odds. Every coefficient is a statement on this third rung, and one exp() climbs it back down to something a human can say.
LiveCoefficients are log-odds bumps; exp(coef) is the odds ratio4 min▶
Because z is the log-odds, each coefficient says: "one unit of this feature adds this much to the log-odds". Adding on a log scale is multiplying on the raw scale - so exp(coef) tells you what one unit of the feature multiplies the odds by. That multiplier is the odds ratio (OR), and it is the currency logistic models are read in. Here is Lumen's near-unregularized fit, dummies vs the affiliate reference channel:
| Feature | exp(coef) = odds ratio | Read it as |
|---|---|---|
| channel = email | ~4.1 | email sessions carry ~4.1x the conversion odds of affiliate |
| channel = direct | ~3.2 | ~3.2x the odds of affiliate |
| returning customer | ~2.8 | ~2.8x the odds of a new visitor, all else equal |
| channel = sms | ~2.7 | ~2.7x the odds of affiliate |
| pages_viewed | ~1.13 | each extra page multiplies the odds by ~1.13 |
| prior_30d_spend | ~1.8 per $100 | coef +0.006 per $1; exp(0.6) is ~1.8 per $100 |
| session_hour | ~1.00 | multiplies the odds by ~1 - the planted noise feature, correctly ignored |
| intercept | log-odds ~ -5.9 | the reference session's starting point, deep in "no" territory |
Notice the model's honesty: it found the strong channels, priced spend and pages sensibly, and gave the decoy feature a multiplier of one. You will verify all of this against the generator's true coefficients in the build.
LiveThe hard rule: an odds ratio is NOT a probability ratio2 min▶
"Returning customers have OR ~2.8" does not mean "returning customers are 2.8x as likely to convert". Odds and probability are different rungs of the ladder, and the ratio of one is not the ratio of the other - the gap widens as probabilities grow. At Lumen's ~3% base rate the two happen to be numerically close, which is exactly why sloppy phrasing survives unchallenged - until someone applies it at a 40% base rate and the claim becomes mathematically impossible.
Self-studysklearn regularizes by default - the C trap3 min▶
Surprise for statisticians: LogisticRegression() is regularized out of the box - L2 penalty, C=1, where C is the inverse regularization strength (small C = strong penalty; the reciprocal of the alpha convention from session 2's ridge card). Great default for prediction; quietly biased for interpretation, because the penalty shrinks every coefficient toward zero and your odds ratios come out closer to 1 than the data says.
The convention this course uses: for clean, readable odds ratios, fit near-unregularized with C=1e6 - the statisticians' habit. For pure prediction pipelines, keep the default and tune C by cross-validation - the ML habit. Both are correct; they answer different questions. This is sklearn section 1.1.11's territory - read the whole section once, it is short and saves careers.
Self-studySolvers in one card - lbfgs, saga, liblinear2 min▶
lbfgs is the default and the right answer most days: fast, handles L2, no drama. saga is the one to reach for when you need L1 or elastic-net penalties or have very large data - but it converges properly only on scaled features. liblinear is the old workhorse with a documented quirk worth knowing: it penalizes the intercept along with the weights, which subtly shifts fitted values - avoid it when you plan to read coefficients. If you ever see a convergence warning, raise max_iter first, check scaling second, switch solvers third.
The loss: why not MSE? 6 min live
Session 2's model minimized squared error, so the obvious move is to reuse it: squash predictions through the sigmoid, measure squared distance to the 0/1 labels, minimize. Obvious - and wrong. Push MSE through a sigmoid and the loss surface stops being a clean bowl: it turns non-convex, a bumpy landscape of flats and dents where an optimizer can settle into a local dip and stall, far from the best weights. Logistic regression instead uses log-loss, which comes straight from maximum likelihood: choose the weights under which the observed labels were most probable. That loss is convex - one bowl, one bottom, and any decent optimizer finds it from anywhere.
LiveConfidently wrong is expensive3 min▶
Log-loss has a personality: it charges for wrongness in proportion to confidence. Predict p = 0.6 for a session that does not convert and you pay a modest fee. Predict p = 0.99 for that same session and the penalty is brutal - the loss grows without bound as your confidence approaches certainty. A model trained on log-loss learns not just to be right, but to be calibrated: to reserve its 0.99s for cases that deserve them.
That is exactly the incentive you want in a conversion model - a scorer that shouts only when it should. Compare naive Bayes in session 6, whose probabilities you will learn not to trust.
Read the machine that made the data ★ 18 min · everyone builds
This build has a punchline no real dataset can offer: because Lumen is generated, we KNOW the true machine. The generator computes z = -5.13 + 0.95*returning + 0.006*spend + 0.11*pages + channel lifts, then rolls the dice. Your job: fit a logistic model that has never seen those numbers, and watch it find them.
Fit in statistician mode. get_dummies(drop_first=True), unscaled features, LogisticRegression(C=1e6, max_iter=8000) on the train split - near-unregularized, so coefficients stay honest.
Print the odds ratios, biggest first. np.exp(coef), sort descending. This is Part 2's table coming off the press: email ~4.1, direct ~3.2, returning ~2.8, sms ~2.7, pages ~1.13, spend ~1.01 per $1, hour ~1.00.
Compare against the truth. The generator used +0.95 on returning: exp(0.95) = 2.6, and you fitted ~2.8 - recovered through 30,000 noisy dice rolls. Spend's 0.006 comes back exactly. The decoy hour lands at ~1.00. The model found the machine that made the data.
The two headline models. Refit b3's numeric-only replica (scaled: spend, pages, hour) - ROC-AUC ~0.61. The full-feature model - ~0.69. Same algorithm; the features carry the signal.
Before session 4 ◐ 25 min
- By hand, from the fitted coefficient +0.006 per $1 of prior spend: what is the odds ratio per $100? Work the exponent (0.006 x 100 = 0.6; exp(0.6) is ~1.8), then check it against the demo's printout.
- Refit the same model with
C=1(sklearn's default) and reprint the odds ratios. Every OR shrinks toward 1 - regularization made visible. Which feature moved most, and why does that make sense? - Write three sentences explaining "email has an odds ratio of about 4.1" to a fictional CMO - no formulas, and mind the hard rule: odds, not probability. Bonus point if sentence three proposes what to do about it.
Three questions before you go 🎯 ◐ 90 seconds
1 · The fitted odds ratio for returning customers is ~2.8. What exactly does that mean?
Odds ratios multiply odds, not probabilities. At Lumen's ~3% base rate the two are numerically close - which is exactly why the sloppy version survives - but at higher base rates they diverge badly. Say "odds" and stay right at every base rate.
2 · Why does logistic regression train on log-loss instead of MSE?
Two reasons, one answer: convexity guarantees the optimizer finds the global best, and the unbounded penalty on confident misses trains calibrated probabilities - the model learns to reserve its 0.99s for cases that earn them.
3 · Where exactly is logistic regression's decision boundary?
z = 0 and p = 0.5 are the same place, because sigma(0) = 0.5. The set of points where w·x + b = 0 is linear - which is why logistic regression's boundary signature in the explorer is the one calm straight seam.
What this session covers
Session 3 covers the logistic-regression core of the anchor sources - sigmoid, odds ladder, coefficients, maximum likelihood - with pseudo-R² named and the solver table condensed to one card. Videos, labs, and certificates stay with the official providers.