Quiz 2

Logistic Regression & Classification Metrics

2155 words
11 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Logistic Regression & Classification Metrics ## 🎯 Learning Objectives - Explain why linear regression fails for classification and how logistic regression fixes it - Understand the sigmoid function and how it produces probabilities - Derive the logistic regression cost function and gradient - Evaluate classificat...

Logistic Regression & Classification Metrics

🎯 Learning Objectives

  • Explain why linear regression fails for classification and how logistic regression fixes it
  • Understand the sigmoid function and how it produces probabilities
  • Derive the logistic regression cost function and gradient
  • Evaluate classification models with accuracy, precision, recall, F1, and AUC-ROC
  • Implement logistic regression using sklearn

📋 Prerequisites

  • Linear Regression — logistic regression is structurally similar but for classification
  • Probability basics — odds, log-odds, probability
  • Gradient descent — same optimization algorithm

📖 Core Content

4.1 Intuition: Why Not Just Use Linear Regression for Classification?

Imagine predicting "will a student pass an exam?" (y=1y=1 = pass, y=0y=0 = fail) from hours studied. If we use linear regression, two things break:
  1. Predictions outside [0,1]: For very few hours, the line might predict -0.2 (meaningless as a probability). For many hours, it might predict 1.3.
  2. Sensitive to outliers: Adding more data points far to the right would tilt the regression line, changing all predictions. Logistic regression fixes this by wrapping the linear model in the sigmoid function, which squashes outputs to the range [0,1] — interpretable as probabilities. (Diagram)

4.2 The Sigmoid Function

σ(z)=11+ez\sigma(z) = \frac{1}{1 + e^{-z}}
Properties:
  • Range: (0, 1) — never exactly 0 or 1
  • σ(0)=0.5\sigma(0) = 0.5 — the decision threshold
  • As z+z \to +\infty, σ(z)1\sigma(z) \to 1
  • As zz \to -\infty, σ(z)0\sigma(z) \to 0
python
# runnable
import numpy as np
import matplotlib.pyplot as plt
z = np.linspace(-10, 10, 100)
sigmoid = 1 / (1 + np.exp(-z))
plt.plot(z, sigmoid, 'b-', linewidth=2)
plt.axhline(y=0.5, color='r', linestyle='--', label='Decision boundary (0.5)')
plt.axvline(x=0, color='gray', linestyle=':', alpha=0.5)
plt.xlabel('z = θᵀx')
plt.ylabel('σ(z) = P(y=1|x)')
plt.title('Sigmoid Function')
plt.grid(True, alpha=0.3)
plt.legend()
plt.show()

4.3 Formal Definition

The Hypothesis (probability of class 1):
hθ(x)=P(y=1x;θ)=11+eθTxh_\theta(x) = P(y=1|x;\theta) = \frac{1}{1 + e^{-\theta^T x}}
Decision Rule:
y^={1if hθ(x)0.50otherwise\hat{y} = \begin{cases} 1 & \text{if } h_\theta(x) \geq 0.5 \\ 0 & \text{otherwise} \end{cases}
The decision boundary is where θTx=0\theta^T x = 0 (since σ(0)=0.5\sigma(0) = 0.5).

4.4 The Cost Function

We can't use MSE for logistic regression because it creates a non-convex cost function (many local minima). Instead, we use log loss (binary cross-entropy):
J(θ)=1mi=1m[y(i)log(hθ(x(i)))+(1y(i))log(1hθ(x(i)))]J(\theta) = -\frac{1}{m} \sum_{i=1}^{m} [y^{(i)} \log(h_\theta(x^{(i)})) + (1-y^{(i)}) \log(1 - h_\theta(x^{(i)}))]
Why this works:
  • If y=1y=1: cost = log(hθ(x))-\log(h_\theta(x)). If hθ(x)1h_\theta(x) \approx 1, cost ≈ 0. If hθ(x)0h_\theta(x) \approx 0, cost → ∞.
  • If y=0y=0: cost = log(1hθ(x))-\log(1 - h_\theta(x)). If hθ(x)0h_\theta(x) \approx 0, cost ≈ 0. If hθ(x)1h_\theta(x) \approx 1, cost → ∞. The gradient (same form as linear regression!):
Jθj=1mi=1m(hθ(x(i))y(i))xj(i)\frac{\partial J}{\partial \theta_j} = \frac{1}{m} \sum_{i=1}^{m} (h_\theta(x^{(i)}) - y^{(i)}) x_j^{(i)}

4.5 Worked Example 1: Hand Calculation

Let's classify students as pass (y=1y=1) or fail (y=0y=0) based on hours studied.
Hours ( xx )Pass ( yy )
10
20
31
41
Step 1: Initialize θ0=0,θ1=0\theta_0 = 0, \theta_1 = 0. Step 2: Compute predictions (all 0.5 since z=0z=0). Step 3: Compute log loss:
J(0,0)=14[0log(0.5)+1log(0.5)+0log(0.5)+1log(0.5)+0log(0.5)]J(0,0) = -\frac{1}{4}[0\cdot\log(0.5) + 1\cdot\log(0.5) + 0\cdot\log(0.5) + 1\cdot\log(0.5) + 0\cdot\log(0.5)]
Wait, let me be more careful. For y=0y=0: cost = log(10.5)=log(0.5)=0.693-\log(1-0.5) = -\log(0.5) = 0.693 For y=1y=1: cost = log(0.5)=0.693-\log(0.5) = 0.693 For our dataset: J=14(0.693+0.693+0.693+0.693)=0.693J = \frac{1}{4}(0.693 + 0.693 + 0.693 + 0.693) = 0.693 Step 4: Gradient descent (one iteration with α=0.1\alpha=0.1):
Jθ0=14[(0.50)+(0.50)+(0.51)+(0.51)]=14[0.5+0.50.50.5]=0\frac{\partial J}{\partial \theta_0} = \frac{1}{4}[(0.5-0) + (0.5-0) + (0.5-1) + (0.5-1)] = \frac{1}{4}[0.5 + 0.5 - 0.5 - 0.5] = 0 Jθ1=14[(0.50)(1)+(0.50)(2)+(0.51)(3)+(0.51)(4)]\frac{\partial J}{\partial \theta_1} = \frac{1}{4}[(0.5-0)(1) + (0.5-0)(2) + (0.5-1)(3) + (0.5-1)(4)] =14[0.5+1.01.52.0]=24=0.5= \frac{1}{4}[0.5 + 1.0 - 1.5 - 2.0] = \frac{-2}{4} = -0.5
Update: θ0=00.1(0)=0\theta_0 = 0 - 0.1(0) = 0, θ1=00.1(0.5)=0.05\theta_1 = 0 - 0.1(-0.5) = 0.05 After many iterations (using sklearn), we get approximately θ=[4,1.6]\theta = [-4, 1.6]. Decision boundary: z=4+1.6x=0    x=2.5z = -4 + 1.6x = 0 \implies x = 2.5 hours. So the model predicts "pass" if hours > 2.5, "fail" otherwise. This matches our intuition — 1-2 hours tends to fail, 3-4 hours tends to pass.

4.6 Multiclass Classification: Softmax

For problems with K > 2 classes (e.g., handwritten digit recognition 0-9), we use softmax regression:
P(y=kx;θ)=eθkTxj=1KeθjTxP(y = k | x; \theta) = \frac{e^{\theta_k^T x}}{\sum_{j=1}^{K} e^{\theta_j^T x}}
This gives a probability distribution over K classes (all values between 0 and 1, summing to 1).
python
# runnable
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
iris = load_iris()
X, y = iris.data, iris.target  # 3 classes of iris flowers
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# One-vs-Rest (default) or multinomial
model = LogisticRegression(multi_class='multinomial', max_iter=200)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
probabilities = model.predict_proba(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
print(f"Sample probabilities: {probabilities[0]}")
print(f"Predicted class: {y_pred[0]}")

4.7 Classification Evaluation Metrics

Confusion Matrix:
Predicted PositivePredicted Negative
Actual PositiveTrue Positive (TP)False Negative (FN)
Actual NegativeFalse Positive (FP)True Negative (TN)
Key Metrics:
MetricFormulaBest ForWhen to Use
AccuracyTP+TNTP+TN+FP+FN\frac{TP + TN}{TP + TN + FP + FN}Balanced classesGeneral performance
PrecisionTPTP+FP\frac{TP}{TP + FP}Minimizing false positivesSpam detection (don't flag good email)
Recall (Sensitivity)TPTP+FN\frac{TP}{TP + FN}Minimizing false negativesDisease detection (don't miss sick patients)
SpecificityTNTN+FP\frac{TN}{TN + FP}Correctly rejecting negativesLegitimate email identification
F1 Score2PrecisionRecallPrecision+Recall2 \cdot \frac{Precision \cdot Recall}{Precision + Recall}Imbalanced classesHarmonic mean of P and R
AUC-ROC: Measures the model's ability to distinguish between classes across all thresholds. AUC = 1: perfect. AUC = 0.5: random. AUC < 0.5: worse than random (flip predictions).
python
# runnable
from sklearn.metrics import confusion_matrix, classification_report, roc_auc_score, roc_curve
import numpy as np
y_true = np.array([0, 0, 1, 1, 0, 1, 0, 1, 1, 0])
y_pred = np.array([0, 1, 1, 1, 0, 1, 0, 0, 1, 0])
print("Confusion Matrix:")
print(confusion_matrix(y_true, y_pred))
print("\nClassification Report:")
print(classification_report(y_true, y_pred))

4.8 Worked Example 2: Computing Metrics

For a spam classifier with: TP=80, FP=10, FN=20, TN=90 Step 1: Total = 200 emails. Step 2:
  • Accuracy = (80+90)/200 = 170/200 = 0.85
  • Precision = 80/(80+10) = 80/90 = 0.889
  • Recall = 80/(80+20) = 80/100 = 0.80
  • F1 = 2(0.889×0.80)/(0.889+0.80) = 2(0.711)/1.689 = 0.842 Interpretation:
  • "85% of all emails were correctly classified"
  • "When the model says spam, it's 88.9% correct"
  • "The model catches 80% of actual spam"
  • "F1 of 0.842 balances precision and recall"

4.9 When to Use / Not Use

When to UseWhen NOT to Use
Binary/multiclass classificationNon-linear decision boundaries (use SVM/kernel)
Need calibrated probabilitiesComplex feature interactions (use random forest)
Baseline classifierVery large feature spaces (p >> n, use regularized)
Interpretability neededIf data is not linearly separable at the feature level

📐 Key Formulas / Concepts

ConceptFormulaNotes
Sigmoidσ(z)=11+ez\sigma(z) = \frac{1}{1+e^{-z}}Maps ℝ→(0,1)
Hypothesishθ(x)=σ(θTx)h_\theta(x) = \sigma(\theta^T x)Probability of class 1
Log Loss1m[ylog(h)+(1y)log(1h)]-\frac{1}{m}\sum[y\log(h) + (1-y)\log(1-h)]Convex, no local minima
Decision Boundaryhθ(x)=0.5h_\theta(x) = 0.5θTx=0\theta^T x = 0
Gradient1m(hθ(x(i))y(i))x(i)\frac{1}{m}\sum(h_\theta(x^{(i)}) - y^{(i)})x^{(i)}Same form as linear regression!
SoftmaxeθkTxjeθjTx\frac{e^{\theta_k^T x}}{\sum_j e^{\theta_j^T x}}Multiclass probabilities
F1 Score2×P×RP+R2 \times \frac{P \times R}{P + R}Harmonic mean

⚠️ Common Pitfalls

Pitfall 1: Using Accuracy on Imbalanced Data

The mistake: Evaluating a fraud detector (99.9% legitimate, 0.1% fraud) on accuracy. Why: Always predicting "not fraud" gives 99.9% accuracy — but misses all fraud! The model is useless. Fix: Use precision, recall, F1, or AUC-ROC. For fraud detection, recall (catching fraud) matters more.

Pitfall 2: Not Setting the Decision Threshold

The mistake: Assuming 0.5 is the optimal threshold. Why: The business needs may demand different tradeoffs. Cancer screening needs high recall (threshold < 0.5). Spam detection needs high precision (threshold > 0.5). Fix: Plot precision-recall curve and pick the threshold that optimizes your business metric.

Pitfall 3: Multicollinearity in Logistic Regression

The mistake: Including highly correlated features without care. Why: Like linear regression, logistic regression coefficients become unstable with correlated features. Standard errors inflate significantly. Fix: Use VIF (Variance Inflation Factor) to detect multicollinearity; remove or combine correlated features.

📝 Practice Questions

Q1: Calculate σ(2) manually.
σ(2)=11+e2=11+0.135=11.135=0.881\sigma(2) = \frac{1}{1 + e^{-2}} = \frac{1}{1 + 0.135} = \frac{1}{1.135} = 0.881
The probability of class 1 is 88.1% when z=2. Q2: With θ = [-1, 0.5], what's the decision boundary equation?
Answer: The decision boundary is where θTx=0\theta^T x = 0: 1+0.5x=0    x=2-1 + 0.5x = 0 \implies x = 2
So if the feature value > 2, predict class 1 (< 2, predict class 0). Q3: For a cancer test: TP=90, FP=10, FN=10, TN=890 out of 1000 patients. Compute accuracy, precision, recall, and F1.
  • Accuracy = (90+890)/1000 = 0.98 (98%)
  • Precision = 90/(90+10) = 0.90 (90%)
  • Recall = 90/(90+10) = 0.90 (90%)
  • F1 = 2(0.9×0.9)/(0.9+0.9) = 0.90 (90%)
Note: Even with 98% accuracy, 10 out of 100 cancer patients are missed (FN=10). Is that acceptable? Q4: Why can't we use MSE for logistic regression?
Answer: MSE creates a non-convex cost function for logistic regression with many local minima. Gradient descent might get stuck in a suboptimal local minimum. Log loss (binary cross-entropy) is convex — it has a single global minimum that gradient descent reliably finds. Q5: In a spam filter, which matters more: precision or recall?
Answer: Precision typically matters more. A false positive (marking legitimate email as spam) is worse than a false negative (letting spam through). The user will be more annoyed by missing important emails than by seeing occasional spam. But this depends on the use case — in an exam pass/fail model, both matter equally. Q6: Convert odds of 4:1 to probability and log-odds.
Odds = P(y=1) / P(y=0) = 4/1 = 4
Probability: P = odds/(1+odds) = 4/5 = 0.80
Log-odds = ln(4) = 1.386
In logistic regression, θTx\theta^T x gives the log-odds. So θTx=1.386\theta^T x = 1.386 corresponds to 80% probability. Q7: AUC = 0.5 means what about the model?
Answer: AUC = 0.5 means the model is no better than random guessing. The ROC curve follows the diagonal line — for every threshold, the true positive rate equals the false positive rate. The model has zero discriminatory power. Q8: Implement logistic regression for 2D Iris data using sklearn
python
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
import numpy as np

iris = load_iris()
# Use only first 2 features for binary classification (setosa vs others)
X = iris.data[:100, :2]  # Only setosa (0) and versicolor (1)
y = iris.target[:100]  # Binary: 0 or 1

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

model = LogisticRegression()
model.fit(X_train, y_train)
print(f"Accuracy: {model.score(X_test, y_test):.3f}")
print(f"Coefficients: {model.coef_}")
print(f"Intercept: {model.intercept_}")
Q9: What is the difference between one-vs-rest and multinomial (softmax) for multiclass?
Answer:
  • One-vs-Rest (OvR): Trains K separate binary classifiers (one per class vs. all others). Each gets its own set of parameters. Simple but probabilities may not sum to 1.
  • Softmax/Multinomial: A single model with K sets of parameters. Produces a proper probability distribution (all classes sum to 1). Preferred when classes are mutually exclusive. Q10: Your model has high precision but low recall. What does this mean?
Answer:
  • High precision: When the model predicts positive, it's usually right (few false positives).
  • Low recall: The model misses many actual positives (many false negatives).
The model is very "cautious" — it only predicts positive when it's very confident, so it misses borderline cases. To improve recall, lower the decision threshold below 0.5. Q11: When would F1 be more appropriate than accuracy?
Answer: F1 is better when classes are imbalanced. Example: 95% legitimate, 5% fraudulent transactions. A model predicting "legitimate" always gets 95% accuracy. F1 captures the model's ability to detect the minority (fraud) class. Always use F1 (or precision/recall) when the positive class < 20% of the data. Q12: Explain the confusion matrix for a COVID test with 1% prevalence, test sensitivity 95%, specificity 99%. Compute PPV.
Out of 10,000 people: 100 sick (TP=95, FN=5), 9900 healthy (TN=9801, FP=99).
PPV (Precision): TP/(TP+FP) = 95/(95+99) = 95/194 = 0.49
Interpretation: Even with 95% sensitivity and 99% specificity, only 49% of positive tests are actually sick! This is because the disease is rare (1% prevalence). This counterintuitive result is the "base rate fallacy."

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.