The coefficients come out for classes_[1], which is B. This page writes everything in terms of \(P(\text{A}|x)\), and flipping the sign of both parameters is what turns one into the other.
The prediction is the class with the highest probability, which with two classes means a threshold of 0.5. That threshold is a choice, not something the model dictates, and further down this page you can move it and watch the decision change.
The log-likelihood, by hand
The log-likelihood of a parameter pair is the sum, over the training points, of the log probability the model gives to the class that was actually observed. Our three labels are B, A, A, so it is
One probability per training point, then pick out the one belonging to the label that was drawn: \(P(\text{A}|x)\) where the label is A, and \(1 - P(\text{A}|x)\) where it is B.
2
LogisticRegression sorts the classes alphabetically and reports the coefficients of the second one, here B. Ours are written for A, and \(s(-z) = 1 - s(z)\), so the two differ by a sign.
by hand: -0.000412
sklearn: -0.000412
log_loss with normalize=False is the negative log-likelihood. The two agree.
Look at the size of that fitted slope, and at how close the log-likelihood is to zero. With these three points every label is predicted almost perfectly, because one straight cut at any \(x\) between 0 and 2 separates the B from the two As. Nothing then stops the fit from making the step steeper and the likelihood larger, and what the numbers above report is not a maximum but wherever the optimizer chose to stop. Three points are not enough to pin a curve down.
Maximum likelihood as a search
The hand computation above evaluates \(\ell\) at a single pair of parameters. Fitting is the search for the pair that makes it as large as possible, and that search is easier to see with enough data to have an answer. The panel below draws sixty points from the same generator, \(P(\text{A}|x) = s(2x - 1)\).
Move the two parameters and watch the log-likelihood. The dashed line is the generator, \(s(2x - 1)\); both of its parameters are values the sliders can take, so you can put our model exactly on top of it. Maximum likelihood picks the parameters that make the observed labels as probable as possible.
Two things are worth doing with it. Set the sliders to the generator, intercept \(-1\) and slope \(2\), and the two curves coincide — but the log-likelihood there, \(-13.01\), is not the best the grid offers. Now raise the slope one notch to \(2.5\) and it improves to \(-12.54\).
That gap is the whole idea. Maximum likelihood aims at the data, not at the generator, and with sixty points the two are close but not equal. The fit is the parameters that best explain the labels we happened to draw, and a different sixty points would move it somewhere else nearby.
Two predictors
Nothing so far used the fact that \(x\) was a single number. With two predictors,
the probability is a surface over the input plane, and the threshold is a horizontal plane cutting through it. Where the two meet is where the decision changes.
That meeting is a straight line, and this is the one thing worth taking away from the picture below. The logistic function is monotone, so the probability is the same wherever \(\beta_0 + \beta_1 x_1 + \beta_2 x_2\) is the same, and that is a straight line.
Left, the probability of class A over the input plane, with the decision threshold as a flat plane through it. Drag the box to turn it. Middle, the level lines of that same surface, labelled by the probability, with the one at the threshold picked out. Right, two hundred points drawn from the model, class A in red and class B in blue, over the decision at every point of a grid in smaller dots. Large coefficients make the surface steep and the level lines crowd together; a threshold away from 0.5 slides the boundary sideways without turning it.
Two things in that last panel are worth separating. The small dots are what the model decides, and they change only when the boundary moves. The large dots are what the generator drew, and near the boundary the same input can come out either way. Even with the parameters that produced the data, some points sit on the wrong side. That is not an error of the fit. It is the noise in the problem, and no classifier can remove it.
Counting mistakes
The cross-entropy is what we fit. It is not always what we report. Once a prediction is a class rather than a probability, the natural summary is the misclassification rate, the average of the zero-one loss
\[
L(y, \hat y) = \begin{cases} 0 & \hat y = y\\ 1 & \hat y \neq y \end{cases}
\]