AiTechWorlds
AiTechWorlds
Logistic regression is the most important classification algorithm you'll learn not because it's the most powerful, but because it builds the conceptual foundation for neural networks, understanding probability outputs, and interpreting ML models.
Despite the name, logistic regression is a classification algorithm, not regression.
Linear regression predicts a continuous number. Logistic regression predicts a probability between 0 and 1, then classifies based on a threshold (default: 0.5).
The core idea: take the linear equation y = wx + b and pass it through the sigmoid function to squash the output to [0, 1]:
sigmoid(x) = 1 / (1 + e^(-x))
Output:
- Close to 0 → class 0 (negative)
- Close to 1 → class 1 (positive)
- 0.5 → decision boundaryimport numpy as np
import matplotlib.pyplot as plt
# The sigmoid function
def sigmoid(x):
return 1 / (1 + np.exp(-x))
x = np.linspace(-10, 10, 100)
plt.plot(x, sigmoid(x))
plt.axhline(y=0.5, color='r', linestyle='--', label='Decision boundary')
plt.xlabel('Linear combination of features')
plt.ylabel('Probability')
plt.title('Sigmoid Function')
plt.legend()
plt.show()from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.preprocessing import StandardScaler
import numpy as np
# Example: Email spam classification
# Features: [word_count, exclamation_marks, contains_unsubscribe, uppercase_ratio]
np.random.seed(42)
n_samples = 1000
X = np.column_stack([
np.random.randint(50, 500, n_samples), # word count
np.random.randint(0, 20, n_samples), # exclamation marks
np.random.randint(0, 2, n_samples), # unsubscribe link
np.random.uniform(0, 0.5, n_samples), # uppercase ratio
])
# Create labels — spam more likely with many exclamation marks + unsubscribe
y = ((X[:, 1] > 10) | (X[:, 2] == 1) & (X[:, 3] > 0.3)).astype(int)
# Split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Scale (important for logistic regression)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Train
model = LogisticRegression(random_state=42, max_iter=1000)
model.fit(X_train_scaled, y_train)
# Evaluate
y_pred = model.predict(X_test_scaled)
y_proba = model.predict_proba(X_test_scaled)[:, 1] # Probability of spam
print(classification_report(y_test, y_pred, target_names=['Not Spam', 'Spam'])) precision recall f1-score support
Not Spam 0.92 0.95 0.93 155
Spam 0.88 0.82 0.85 45
accuracy 0.91 200Precision: Of all emails we called spam, 88% actually were spam. Recall: Of all actual spam emails, we caught 82% of them. F1-score: Harmonic mean of precision and recall (useful when classes are imbalanced).
import seaborn as sns
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Not Spam', 'Spam'],
yticklabels=['Not Spam', 'Spam'])
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.title('Confusion Matrix')
plt.show()
# The four cells:
# True Negative (TN): Correctly classified as not spam
# False Positive (FP): Wrongly called spam (sent real email to junk)
# False Negative (FN): Missed spam (spam got through)
# True Positive (TP): Correctly caught spamAdjusting the classification threshold shifts the tradeoff between precision and recall:
# Lower threshold → catch more spam (higher recall, lower precision)
# Higher threshold → only flag obvious spam (higher precision, lower recall)
thresholds = [0.3, 0.5, 0.7]
for t in thresholds:
y_pred_t = (y_proba >= t).astype(int)
cm = confusion_matrix(y_test, y_pred_t)
tp = cm[1, 1]
fp = cm[0, 1]
fn = cm[1, 0]
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
print(f"Threshold {t}: Precision={precision:.2f}, Recall={recall:.2f}")Which matters more depends on your problem:
feature_names = ['word_count', 'exclamation_marks', 'unsubscribe', 'uppercase_ratio']
coefs = pd.Series(model.coef_[0], index=feature_names).sort_values()
coefs.plot(kind='barh', color=['red' if c < 0 else 'blue' for c in coefs])
plt.title('Feature Coefficients (positive = pushes toward Spam)')
plt.axvline(x=0, color='black', linestyle='-')
plt.show()A positive coefficient means the feature pushes toward class 1 (spam). A negative coefficient pushes toward class 0 (not spam). Coefficients are interpretable when features are scaled.
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# multi_class='auto' handles multi-class automatically
model = LogisticRegression(multi_class='auto', solver='lbfgs', max_iter=1000)
model.fit(X_train, y_train)
print(f"Accuracy: {model.score(X_test, y_test):.3f}")
print(classification_report(y_test, model.predict(X_test), target_names=iris.target_names))Use it when:
Consider alternatives when:
Next lesson: Decision Trees a powerful non linear classifier that makes interpretable decisions.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises