2.2 Regresia logistică
În ciuda numelui, este un model de clasificare: răspunde la întrebări de tip da/nu — are diabet sau nu, e spam sau nu — cu o probabilitate între 0 și 1.
Teorie
Clasificare binară
La regresie prezicem un număr oarecare; la clasificare binară prezicem o clasă: 0 sau 1.
Trucul regresiei logistice: calculează întâi un scor liniar
z = w₁x₁ + … + wₙxₙ + b, apoi îl transformă în probabilitate.
Funcția sigmoid
σ(z) = 1 / (1 + e⁻ᶻ)Sigmoidul „strivește" orice număr real în intervalul (0, 1): pentru z foarte negativ → aproape 0, pentru z = 0 → exact 0.5, pentru z foarte pozitiv → aproape 1. Rezultatul se citește ca probabilitatea clasei 1. Predicția finală: clasa 1 dacă probabilitatea ≥ 0.5 (prag implicit, care poate fi modificat — vezi lecția 4.4).
Interpretarea rezultatelor
predict_proba întoarce probabilitățile, predict doar clasa. Un pacient cu
probabilitate 0.93 e o predicție sigură; unul cu 0.51 e la limită — în aplicații medicale asta
contează enorm. Coeficienții pozitivi împing spre clasa 1, cei negativi spre clasa 0.
Implementarea din scikit-learn
from sklearn.linear_model import LogisticRegression
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
model.predict(X_val) # clase: [0, 1, 1, ...]
model.predict_proba(X_val) # probabilități: [[0.9, 0.1], ...]
model.coef_, model.intercept_ # w și b
Problemă rezolvată: diagnosticarea diabetului
Pe baza analizelor (glucoză, tensiune, BMI, vârstă), prezicem dacă pacientul are diabet (1) sau nu (0) — clasificare binară pură.
Soluția pas cu pas
1. Analizele de sânge cu valoarea 0 sunt de fapt valori lipsă (glucoză 0 nu există) → le înlocuim cu mediana. 2. Standardizăm. 3. Regresie logistică + verificăm și F1, nu doar acuratețea (clasele pot fi dezechilibrate).
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import f1_score, accuracy_score
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
feats = [c for c in train.columns if c not in ("SampleID", "diabet")]
# 0 fiziologic imposibil = valoare lipsă
for col in ["glucoza", "tensiune", "bmi"]:
med = train.loc[train[col] > 0, col].median()
train[col] = train[col].replace(0, med)
test[col] = test[col].replace(0, med)
X_tr, X_va, y_tr, y_va = train_test_split(train[feats], train["diabet"],
test_size=0.2, random_state=42,
stratify=train["diabet"])
sc = StandardScaler()
model = LogisticRegression(max_iter=1000)
model.fit(sc.fit_transform(X_tr), y_tr)
pred_va = model.predict(sc.transform(X_va))
print("Acc:", accuracy_score(y_va, pred_va), "F1:", f1_score(y_va, pred_va))
sc = StandardScaler()
model.fit(sc.fit_transform(train[feats]), train["diabet"])
pd.DataFrame({
"SampleID": test["SampleID"],
"diabet": model.predict(sc.transform(test[feats]))
}).to_csv("submission.csv", index=False)
Pentru mai multe puncte: încearcă praguri diferite de decizie sau un model ansamblu (lecția 2.6).
Probleme propuse
Calculează σ(z) pentru z ∈ {−4, −1, 0, 1, 4} și desenează funcția cu Matplotlib. La ce valoare a lui z probabilitatea trece de 0.9?
Pe problema diabetului, compară F1-scorul pentru praguri de 0.3, 0.5 și 0.7 aplicate pe
predict_proba. De ce ar prefera un doctor pragul 0.3?
Problemă de la Simularea OJIA — același tipar, date medicale mai bogate.
Clasificare binară: banca aprobă sau nu împrumutul.