Hồi quy Logistic
Mục tiêu
Phần tiêu đề “Mục tiêu”Sau bài này, bạn sẽ:
- Hiểu vì sao bài toán phân loại nhị phân (binary classification) cần một mô hình cho ra xác suất, và vì sao hồi quy tuyến tính rồi cắt ngưỡng không ổn.
- Đọc được mô hình hồi quy logistic (logistic regression) theo ba cách: xác suất qua hàm sigmoid, log-odds tuyến tính, và ranh giới quyết định (decision boundary) .
- Tự dẫn được hàm mất mát log loss từ hợp lý cực đại (maximum likelihood), và gradient của nó.
- Cài đặt được hồi quy logistic bằng gradient descent và bằng scikit-learn, hiểu tham số
C, và diễn giải hệ số qua odds.
Cần biết trước
Phần tiêu đề “Cần biết trước”- Hồi quy tuyến tính, thuộc phần Học máy (Đã học)
- Gradient Descent, thuộc phần Học máy (Đã học)
- Xác suất thống kê, thuộc phần Toán cho AI (Đã học)
Trực giác
Phần tiêu đề “Trực giác”Thầy chủ nhiệm ghi lại số giờ ôn thi trong tuần trước kỳ thi của 18 sinh viên, và kết quả: đậu hay trượt. Số liệu dưới đây là dữ liệu tự tạo cho bài học.
| Kết quả | Số giờ ôn thi |
|---|---|
| Trượt (9 bạn) | 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4.5, 6 |
| Đậu (9 bạn) | 4, 5, 5.5, 6.5, 7, 7.5, 8, 9, 10 |
Nhìn qua là thấy: ôn ít thì hay trượt, ôn nhiều thì hay đậu, ở giữa có vùng lẫn lộn (bạn 4 giờ đậu, bạn 4.5 giờ và 6 giờ trượt). Thầy muốn trả lời: một bạn ôn 5 giờ thì khả năng đậu là bao nhiêu?
Đây là bài toán phân loại (classification): nhãn chỉ có hai giá trị, 1 (đậu) hoặc 0 (trượt). Thứ thầy cần không chỉ là “đậu hay trượt”, mà là một xác suất: 90% và 51% đều là “đoán đậu”, nhưng ý nghĩa khác hẳn nhau.
Thử hồi quy tuyến tính rồi cắt ngưỡng
Phần tiêu đề “Thử hồi quy tuyến tính rồi cắt ngưỡng”Cách đầu tiên ai cũng nghĩ tới: coi 0 và 1 là số, khớp một đường thẳng như bài Hồi quy tuyến tính, rồi đoán “đậu” khi giá trị dự đoán từ 0.5 trở lên. Với 18 bạn, đường bình phương tối thiểu là . Ngưỡng 0.5 rơi vào giờ, và 16/18 bạn được đoán đúng. Nghe có vẻ ổn, nhưng có hai chỗ hỏng.
Thứ nhất, con số dự đoán không phải xác suất. Bạn ôn 0 giờ được , bạn ôn 10 giờ được . Xác suất âm hay lớn hơn 1 đều vô nghĩa.
Thứ hai, đường thẳng bị kéo bởi những điểm “quá đúng”. Thêm một bạn ôn 30 giờ, và tất nhiên đậu. Bạn này chẳng làm bài toán khó thêm chút nào. Nhưng đường thẳng phải với tới điểm , nên nó nằm nghiêng hẳn xuống: . Ngưỡng dời từ 4.83 sang 5.53 giờ, và hai bạn ôn 5 giờ và 5.5 giờ, vốn đã đậu, giờ bị đoán trượt: trên 18 bạn cũ chỉ còn đúng 14. Nguyên nhân là bình phương sai số phạt bạn 30 giờ vì chưa bằng đúng 1, dù với phân loại, đoán bạn ấy “rất chắc đậu” là đủ.
Ép đầu ra vào khoảng (0, 1)
Phần tiêu đề “Ép đầu ra vào khoảng (0, 1)”Thứ cần là một đường cong: đi gần 0 khi ôn rất ít, gần 1 khi ôn rất nhiều, và chuyển từ 0 sang 1 ở vùng lẫn lộn. Ở hai đầu, đường phải nằm ngang, để bạn 30 giờ đã ở sát 1 thì không kéo gì thêm. Đó là đường chữ S, và hồi quy logistic chính là cách khớp đường chữ S này.
Bài toán của bài là: từ các đặc trưng của một mẫu, đoán xác suất mẫu đó thuộc lớp 1, bằng một đường cong chữ S, và chọn đường cong làm cho dữ liệu đã thấy có khả năng xảy ra cao nhất.
Lý thuyết
Phần tiêu đề “Lý thuyết”Phát biểu bài toán
Phần tiêu đề “Phát biểu bài toán”Có mẫu. Mẫu thứ có vectơ đặc trưng gồm số và nhãn . Lớp 1 gọi là lớp dương (positive class), lớp 0 là lớp âm (negative class). Với 18 sinh viên, , , là số giờ ôn.
Hồi quy logistic làm hai bước. Bước một giống hệt hồi quy tuyến tính: tính một điểm số
với là trọng số, là hệ số tự do. là một số thực bất kỳ, gọi là logit. Bước hai đưa qua hàm sigmoid để được một xác suất:
Vậy ở bài này không còn là “giá trị dự đoán của ” như hồi quy tuyến tính, mà là xác suất mô hình gán cho lớp 1. Xác suất của lớp 0 là .
Hàm sigmoid
Phần tiêu đề “Hàm sigmoid”Nhìn vào công thức để thấy vì sao nó cho đường chữ S:
- rất lớn: gần 0, nên gần .
- rất âm: rất lớn, nên gần 0.
- : , nên .
Vì với mọi , mẫu số luôn lớn hơn 1, nên luôn nằm trong khoảng , không bao giờ chạm đúng 0 hay 1. Đường còn đối xứng quanh điểm : . Vài giá trị:
| 0.0025 | 0.018 | 0.1192 | 0.5 | 0.8808 | 0.982 | 0.9975 |
Đường dốc nhất quanh , và gần như nằm ngang khi vượt quá 5: đúng hình dạng mà mục Trực giác cần. Hình ở mục Minh họa vẽ đường này.
Odds và log-odds: đọc mô hình như một đường thẳng
Phần tiêu đề “Odds và log-odds: đọc mô hình như một đường thẳng”Odds của một xác suất là tỉ số : khả năng xảy ra chia cho khả năng không xảy ra. Xác suất 0.8 có odds là , hay “4 ăn 1”. Xác suất 0.5 có odds 1. Odds đi từ 0 tới vô cùng.
Hãy giải ngược để tìm . Lấy nghịch đảo hai vế, trừ 1, rồi lấy :
Dòng thứ hai trừ 1 ở hai vế và quy đồng . Dòng thứ ba lật phân số (nên thành ), rồi lấy hai vế. Vế trái là log-odds, cũng gọi là logit của . Vậy:
Điều này cho cách đọc hệ số. Tăng thêm 1 đơn vị, giữ các đặc trưng khác nguyên, thì log-odds tăng đúng , nên odds nhân với :
Ở ô code đầu tiên, mô hình của 18 sinh viên có , , nên mỗi giờ ôn thêm nhân odds đậu với . Bạn ôn 4 giờ có , odds 0.386; bạn ôn 5 giờ có , odds 1.365, đúng gấp 3.54 lần. Để ý: xác suất không tăng một lượng cố định. Từ 4 lên 5 giờ, xác suất tăng 0.3; từ 9 lên 10 giờ, nó gần như đứng yên vì đã sát 1. Hệ số âm thì , odds giảm.
Ranh giới quyết định
Phần tiêu đề “Ranh giới quyết định”Muốn ra một lớp cụ thể, ta so với một ngưỡng (threshold), mặc định 0.5: đoán lớp 1 khi . Vì là hàm tăng và :
Tập các điểm có là ranh giới quyết định. Với một đặc trưng, đó là một điểm: giờ. Với hai đặc trưng, đó là đường thẳng ; với đặc trưng, là một siêu phẳng (hyperplane). Đường cong chữ S chỉ nằm ở khâu đổi điểm số thành xác suất, còn ranh giới luôn phẳng. Vì vậy hồi quy logistic là một bộ phân loại tuyến tính (linear classifier).
Ngưỡng 0.5 chỉ là mặc định. Khi bỏ sót lớp dương nguy hiểm hơn báo nhầm (ví dụ sàng lọc bệnh), người ta hạ ngưỡng. Chọn ngưỡng và đánh giá bộ phân loại kỹ hơn độ chính xác là nội dung bài Đánh giá mô hình: Accuracy, Precision, Recall, F1.
Hàm mất mát: từ hợp lý cực đại tới log loss
Phần tiêu đề “Hàm mất mát: từ hợp lý cực đại tới log loss”Cần một con số đo mô hình tốt hay tệ. Ý tưởng của hợp lý cực đại: chọn tham số làm cho dữ liệu đã quan sát có xác suất xảy ra cao nhất theo mô hình.
Bước 1: xác suất của một mẫu. Mô hình nói và . Gộp hai trường hợp vào một công thức:
Thử lại: thì thừa số thứ hai là , còn lại . thì thừa số thứ nhất là , còn lại . Đây là phân phối Bernoulli.
Bước 2: xác suất của cả tập dữ liệu. Coi các mẫu độc lập với nhau, xác suất để cả nhãn xảy ra đúng như đã thấy là tích:
Đại lượng này, xem như hàm của tham số, gọi là likelihood. Ta muốn làm nó lớn nhất.
Bước 3: lấy . Tích của nhiều số nhỏ hơn 1 rất nhanh tiến về 0. Với mô hình tốt nhất cho 18 sinh viên, likelihood chỉ là 0.0062; với vài nghìn mẫu, máy tính làm tròn nó thành 0. Vì là hàm tăng, làm lớn cũng là làm lớn . Dùng và :
Bước 4: đổi thành bài toán làm nhỏ. Quen với việc làm nhỏ hàm mất mát, ta đổi dấu và chia cho để lấy trung bình. Được log loss, còn gọi là binary cross-entropy:
Làm nhỏ đúng là làm lớn likelihood, vì .
Đọc từng mẫu: mỗi mẫu chỉ đóng góp của xác suất mô hình gán cho nhãn đúng. Gán 0.9 cho nhãn đúng thì mất 0.105; gán 0.5 thì mất 0.693; gán 0.1 thì mất 2.303; gán gần 0 thì mất gần vô cùng. Log loss phạt rất nặng những lần sai mà tự tin. Trong 18 sinh viên, hai mẫu bị phạt nặng nhất là hai bạn bị đoán sai: bạn ôn 4 giờ mà đậu (, mất ) và bạn ôn 6 giờ mà trượt (, mất ). Trung bình trên 18 bạn, . Mô hình “không biết gì”, , , cho mọi bạn 0.5, có .
Vì sao không dùng MSE
Phần tiêu đề “Vì sao không dùng MSE”Sao không giữ MSE với ? Xét một mẫu có và nhìn mất mát theo :
- MSE: . Khi rất âm, nó nằm ngang ở gần 1; khi rất dương, nằm ngang ở gần 0. Một đường đi từ nằm ngang, xuống dốc, rồi lại nằm ngang có dạng chữ S, không phải cái bát: nó không lồi. Cộng nhiều mẫu lại, mặt mất mát có những vùng gần như phẳng, nơi gradient descent bò rất chậm.
- Log loss: . Khi rất âm, nó tăng gần như theo đường thẳng , không hề nằm ngang. Sai càng nặng, dốc càng rõ.
Bằng số: với (, sai rất tự tin), đạo hàm theo của MSE chỉ là , của log loss là , mạnh hơn khoảng 200 lần. Mục sau cho thấy vì sao.
Gradient của log loss
Phần tiêu đề “Gradient của log loss”Gradient descent cần đạo hàm riêng của theo từng và . Xét một mẫu, bỏ chỉ số : , với và . Đây là hàm hợp ba tầng, nên dùng quy tắc hàm hợp (chain rule):
Bước 1: đạo hàm của sigmoid. Viết . Đạo hàm của là , nhân với đạo hàm của là :
Dòng thứ hai tách phân số thành tích. Dòng thứ ba dùng . Vậy . Thừa số này lớn nhất (0.25) ở và gần 0 ở hai đầu: đó là lý do MSE qua sigmoid bò chậm.
Bước 2: đạo hàm của theo . Đạo hàm của là ; đạo hàm của theo là :
Dòng thứ hai quy đồng mẫu số. Dòng thứ ba phá ngoặc tử số: .
Bước 3: ghép lại. , nên và . Nhân ba thừa số:
Thừa số ở mẫu và ở tử triệt tiêu nhau. Đó là vì sao log loss không bò chậm khi sai tự tin: đạo hàm theo chỉ còn .
Bước 4: trung bình trên mẫu. là trung bình của các , nên đạo hàm của nó là trung bình các đạo hàm:
Viết gọn bằng ma trận ( hàng, mỗi hàng một mẫu, chưa có cột số 1) và vectơ chứa các : .
Huấn luyện bằng gradient descent
Phần tiêu đề “Huấn luyện bằng gradient descent”Cho gradient bằng 0 thì được các phương trình có bên trong, không giải ra công thức được như phương trình chuẩn. Nên ta dùng gradient descent:
Tin tốt: log loss là hàm lồi theo . Theo , mất mát của một mẫu có đạo hàm và đạo hàm bậc hai , tức cong lên như cái bát; mà lại tuyến tính theo tham số, nên tổng các mẫu vẫn lồi. Không có cực tiểu cục bộ nào để mắc kẹt. scikit-learn mặc định không dùng gradient descent thường mà dùng L-BFGS, một thuật toán dùng thêm thông tin về độ cong để đi ít bước hơn, nhưng đáy nó tìm tới là cùng một đáy.
Regularization trong scikit-learn
Phần tiêu đề “Regularization trong scikit-learn”LogisticRegression của scikit-learn mặc định có phạt L2, như Ridge ở bài Ridge, Lasso, Elastic Net. Từ bản 1.8, tài liệu viết hàm mục tiêu (khi các mẫu có trọng số bằng nhau) là:
Clà nghịch đảo của độ mạnh phạt. So với dạng của bài Regularization, .Cnhỏ là phạt mạnh,Clớn là phạt yếu. Mặc địnhC=1.- không bị phạt (với solver mặc định
lbfgs). - Muốn tắt phạt, tài liệu bản 1.8 khuyên
C=np.inf(tham sốpenaltyđã bị đánh dấu sắp bỏ). Bản 1.8.0 chạy trên trang lại in một cảnh báo thừa khi gặpC=np.inf, nên các ô code dùngC=1e10: phạt nhỏ tới mức không đổi kết quả. - Nên chuẩn hóa đặc trưng, vì cùng lý do như Ridge: phạt đối xử mọi như nhau.
Phạt còn cứu một tình huống mà không phạt thì hỏng: khi có một siêu phẳng tách hẳn hai lớp (linearly separable). Lúc đó, nhân và lên gấp đôi thì ranh giới giữ nguyên, nhưng mọi bị đẩy sát 0 hoặc 1 hơn, nên log loss lại giảm. Không có đáy: các hệ số phình ra mãi. Ô code thứ ba gặp đúng chuyện này.
Giới hạn
Phần tiêu đề “Giới hạn”- Ranh giới luôn phẳng. Hai lớp xếp thành vòng tròn lồng nhau thì không đường thẳng nào tách được. Có thể thêm đặc trưng như , (giống hồi quy đa thức), hoặc dùng mô hình khác như ở bài K-Nearest Neighbors và Decision Tree và Random Forest.
- Chỉ hai lớp. Ba lớp trở lên thì dùng softmax thay cho sigmoid, ở bài Hồi quy Softmax.
- Xác suất chỉ đáng tin khi mô hình đúng dạng. Log-odds thật không tuyến tính theo đặc trưng thì xác suất mô hình đưa ra có thể lệch, dù độ chính xác vẫn cao.
- Hệ số khó đọc khi đặc trưng tương quan mạnh (hộp thứ ba ở mục Lỗi hay gặp).
Minh họa
Phần tiêu đề “Minh họa”Hình dưới vẽ hàm sigmoid theo . Hãy nhìn vào hai đầu đường cong, nơi nó nằm ngang sát hai đường tiệm cận 0 và 1, và vào điểm giữa . Các chấm là 18 sinh viên, đặt tại của mô hình khớp ở ô code đầu tiên, ở độ cao 1 nếu đậu, 0 nếu trượt. Đường dọc chính là ranh giới quyết định, ứng với 4.75 giờ ôn.
Ví dụ code
Phần tiêu đề “Ví dụ code”Ba ô dưới đây chạy độc lập, ô nào cũng tự tạo dữ liệu. Ô chạy đầu tiên lâu hơn một chút, vì trình duyệt phải tải thêm scikit-learn; ô thứ hai còn tải thêm Matplotlib.
Gradient descent bằng NumPy
Phần tiêu đề “Gradient descent bằng NumPy”Ô đầu tiên cài đặt đúng phần Lý thuyết: sigmoid, log loss, gradient , xuất phát từ với , dừng khi độ lớn gradient dưới . Cuối ô là LogisticRegression của scikit-learn để đối chiếu.
Hồi quy logistic bằng gradient descent
import numpy as npfrom sklearn.linear_model import LogisticRegression
# 18 sinh viên (dữ liệu tự tạo): số giờ ôn thi và kết quả (1 = đậu).hours = np.array([0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 9, 10])passed = np.array([0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1])
def sigmoid(z): return 1 / (1 + np.exp(-z))
def log_loss(p, y): # binary cross-entropy, trung bình trên m mẫu return -np.mean(y * np.log(p) + (1 - y) * np.log(1 - p))
w, b, eta = 0.0, 0.0, 0.2 # xuất phát từ 0, tốc độ học 0.2for step in range(100_000): p = sigmoid(w * hours + b) # y^ = P(đậu | số giờ) grad_w = np.mean((p - passed) * hours) # dL/dw grad_b = np.mean(p - passed) # dL/db if np.hypot(grad_w, grad_b) < 1e-6: # gradient đủ nhỏ thì dừng break w, b = w - eta * grad_w, b - eta * grad_bprint(f"GD stopped after {step} steps")print(f"GD: w = {w:.3f}, b = {b:.3f}, log loss = {log_loss(p, passed):.4f}")print(f"threshold -b/w = {-b / w:.3f} h, odds ratio e^w = {np.exp(w):.2f}")for h in [2, 4, 6, 8]: print(f"P(pass | {h} h) = {sigmoid(w * h + b):.3f}")
# scikit-learn: C rất lớn nghĩa là gần như không phạt (xem bài).model = LogisticRegression(C=1e10).fit(hours.reshape(-1, 1), passed)w_sk, b_sk = model.coef_[0, 0], model.intercept_[0]print(f"sklearn: w = {w_sk:.3f}, b = {b_sk:.3f}")print(f"sklearn P(pass | 4 h) = {model.predict_proba([[4]])[0, 1]:.3f}")Lần chạy đầu cần tải Python, khoảng 10 MB.
GD dừng sau 7540 bước với , , log loss 0.2826, khớp scikit-learn tới ba chữ số. Ngưỡng giờ, mỗi giờ ôn thêm nhân odds đậu với 3.54. Xác suất đậu đi 0.030, 0.278, 0.828, 0.984 khi số giờ đi 2, 4, 6, 8: tăng nhanh nhất quanh ngưỡng, chậm dần ở hai đầu, đúng hình chữ S.
Hơn 7500 bước là nhiều, vì số giờ chưa chuẩn hóa: như bài Gradient Descent, đặc trưng nằm xa 0 làm mặt mất mát hẹp và dài. Hãy thử đổi eta thành 0.05: GD vẫn tới cùng đáp án, nhưng mất khoảng 30 000 bước.
Đường thẳng và đường cong chữ S
Phần tiêu đề “Đường thẳng và đường cong chữ S”Ô thứ hai kiểm lại các số ở mục Trực giác: khớp hồi quy tuyến tính và hồi quy logistic trên 18 sinh viên, rồi trên 19 sinh viên (thêm bạn ôn 30 giờ), in ngưỡng và độ chính xác trên 18 bạn đầu, và vẽ bốn đường.
Hồi quy tuyến tính và hồi quy logistic
import numpy as npimport matplotlib.pyplot as pltfrom sklearn.linear_model import LinearRegression, LogisticRegression
# 18 sinh viên như ô trước, rồi thêm một bạn ôn 30 giờ và đậu.hours = np.array([0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6, 6.5, 7, 7.5, 8, 9, 10])passed = np.array([0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1])X, X30 = hours.reshape(-1, 1), np.append(hours, 30).reshape(-1, 1)y30 = np.append(passed, 1)
grid = np.linspace(0, 32, 300).reshape(-1, 1)fig, ax = plt.subplots(figsize=(7, 4))ax.scatter(X30[:, 0], y30, color="black", zorder=3, label="students")for name, Xt, yt, style in [("18", X, passed, "-"), ("19", X30, y30, "--")]: lin = LinearRegression().fit(Xt, yt) log = LogisticRegression(C=1e10).fit(Xt, yt) # gần như không phạt a, c = lin.coef_[0], lin.intercept_ w, b = log.coef_[0, 0], log.intercept_[0] acc = np.mean((lin.predict(X) >= 0.5) == passed) # trên 18 bạn đầu print(f"{name} students: line y = {a:.4f} x + {c:.4f}") print(f" line: y^(0) = {c:.3f}, y^(10) = {a * 10 + c:.3f}, " f"y^(30) = {a * 30 + c:.3f}") print(f" line threshold = {(0.5 - c) / a:.2f} h, accuracy = {acc:.3f}") print(f" logistic threshold = {-b / w:.2f} h, " f"accuracy = {log.score(X, passed):.3f}") ax.plot(grid, lin.predict(grid), "tab:orange", ls=style, label=f"linear, {name} students") ax.plot(grid, log.predict_proba(grid)[:, 1], "tab:blue", ls=style, label=f"logistic, {name} students")ax.axhline(0.5, color="gray", lw=0.8)ax.set_xlabel("hours of study")ax.set_ylabel("prediction")ax.set_ylim(-0.3, 1.5)ax.legend(fontsize=8)plt.show()Lần chạy đầu cần tải Python, khoảng 10 MB.
Với 18 bạn, hai cách cho ngưỡng gần nhau (4.83 và 4.75 giờ) và cùng đoán đúng 0.889, tức 16/18. Nhưng đường thẳng cho ở 0 giờ, ở 10 giờ và ở 30 giờ: không đọc như xác suất được. Thêm bạn 30 giờ, đường thẳng nghiêng xuống, ngưỡng dời sang 5.53 giờ, độ chính xác trên 18 bạn cũ tụt còn 0.778. Đường chữ S thì gần như không động đậy: ngưỡng vẫn 4.75 giờ. Lý do nằm ở gradient: bạn 30 giờ có sát 1, nên gần 0, gần như không đẩy tham số.
Dữ liệu thật: chẩn đoán u vú
Phần tiêu đề “Dữ liệu thật: chẩn đoán u vú”Ô thứ ba dùng bộ load_breast_cancer có sẵn trong scikit-learn: 569 khối u, 30 đặc trưng đo từ ảnh chụp nhân tế bào (bán kính, độ sần bề mặt, độ lõm…). Nhãn 1 là lành tính (benign), nhãn 0 là ác tính (malignant). Ô chia 75% train, 25% test giữ đúng tỉ lệ hai lớp (stratify=y), đặt StandardScaler trong pipeline, khớp với C=1 (mặc định) và C=1e10 (gần như không phạt), rồi đọc ba hệ số lớn nhất của mô hình mặc định.
Hồi quy logistic trên bộ dữ liệu u vú
import numpy as npfrom sklearn.datasets import load_breast_cancerfrom sklearn.linear_model import LogisticRegressionfrom sklearn.model_selection import train_test_splitfrom sklearn.pipeline import make_pipelinefrom sklearn.preprocessing import StandardScaler
# 569 khối u, 30 đặc trưng. Nhãn: 0 = ác tính, 1 = lành tính.data = load_breast_cancer()X, y = data.data, data.targetprint(f"m = {X.shape[0]}, n = {X.shape[1]}, benign = {y.mean():.3f}")X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.25, stratify=y, random_state=0)
for C in [1.0, 1e10]: # mặc định (phạt L2, C = 1) và gần như không phạt model = make_pipeline(StandardScaler(), LogisticRegression(C=C, max_iter=10_000)) model.fit(X_train, y_train) w = model[-1].coef_[0] print(f"C = {C:g}: train acc = {model.score(X_train, y_train):.3f}, " f"test acc = {model.score(X_test, y_test):.3f}, " f"max |w| = {np.abs(w).max():.1f}")
# Mô hình mặc định: 3 hệ số lớn nhất về trị tuyệt đối.model = make_pipeline(StandardScaler(), LogisticRegression())model.fit(X_train, y_train)w = model[-1].coef_[0]for j in np.argsort(-np.abs(w))[:3]: print(f"{data.feature_names[j]:>19}: w = {w[j]:+.3f}, " f"e^w = {np.exp(w[j]):.3f}")
# Xác suất lành tính của 5 khối u đầu tiên trong tập test.proba = model.predict_proba(X_test[:5])[:, 1]print("P(benign):", " ".join(f"{p:.3f}" for p in proba))print("predicted:", model.predict(X_test[:5]), " true:", y_test[:5])Lần chạy đầu cần tải Python, khoảng 10 MB.
- Mặc định
C=1: độ chính xác test 0.958, tức 137/143 khối u, hệ số lớn nhất về trị tuyệt đối chỉ 1.2. C=1e10: train đúng 1.000, tức có một siêu phẳng tách hẳn hai lớp trên tập train, và hệ số lớn nhất phình tới 205.9, đúng như mục Regularization. Test tụt còn 0.944: mô hình overfit.- Ba hệ số lớn nhất đều âm: radius error (độ dao động bán kính giữa các nhân tế bào, ), worst texture (độ sần ở vùng tệ nhất, ), mean concave points (số điểm lõm trung bình, ). Đặc trưng đã chuẩn hóa, nên đọc là: tăng một độ lệch chuẩn radius error, giữ các đặc trưng khác nguyên, thì odds lành tính nhân với , tức còn chưa tới một phần ba. Hệ số âm ở đây nghĩa là nghiêng về ác tính, vì lớp 1 là lành tính.
- Năm khối u đầu tiên của tập test có xác suất lành tính 0.996, 0.000, 0.000, 1.000, 0.003, và cả năm được đoán đúng. “0.000” chỉ là làm tròn: sigmoid không bao giờ cho đúng 0.
Lỗi hay gặp
Phần tiêu đề “Lỗi hay gặp”Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Tóm tắt và đọc thêm
Phần tiêu đề “Tóm tắt và đọc thêm”Ý chính:
- Hồi quy logistic tính rồi đưa qua sigmoid: . Khác đường thẳng, đầu ra luôn trong và không bị kéo bởi những điểm “quá đúng”.
- Log-odds tuyến tính: . Tăng một đơn vị thì odds nhân . Ranh giới quyết định ở ngưỡng 0.5 là siêu phẳng .
- Log loss là lần log-likelihood: Hàm mất mát này lồi, phạt nặng lỗi sai tự tin, và có gradient , cùng dạng với hồi quy tuyến tính. Không có nghiệm dạng đóng, nên huấn luyện bằng gradient descent hoặc L-BFGS.
LogisticRegressionmặc định phạt L2 vớiC=1, :Cnhỏ là phạt mạnh. Phạt giữ hệ số hữu hạn khi dữ liệu tách được hoàn toàn.
Đọc thêm:
- Vũ Hữu Tiệp (2017). Machine Learning cơ bản, Bài 10: Logistic Regression. Tiếng Việt, có dẫn hàm mất mát từ likelihood và ví dụ Python với số giờ ôn thi. Ký hiệu khác: là số mẫu, đầu ra sigmoid viết , hàm mất mát là tổng, không chia .
- scikit-learn developers (2007–2026). scikit-learn 1.8 User Guide: Logistic regression, mục 1.1.11. Hàm mục tiêu chính xác có
C, bảng solver, và vì sao phạt được bật sẵn. - Jurafsky, D., Martin, J. H. (2026). Speech and Language Processing, bản nháp 3rd ed., chương 4: Logistic Regression and Text Classification (PDF). Dẫn cross-entropy và gradient rất kỹ, ví dụ là phân loại văn bản.
- Ma, T., Ng, A. (2026). CS229 Lecture Notes (PDF), mục 2.1: Logistic regression. Dẫn gradient từ log-likelihood, ký hiệu cho và làm lớn log-likelihood bằng gradient ascent.
- Cox, D. R. (1958). The Regression Analysis of Binary Sequences. Journal of the Royal Statistical Society: Series B 20(2), 215–232. Một trong những bài báo đầu tiên đưa hồi quy logistic vào thống kê.
Trình duyệt đang chặn lưu dữ liệu. Tiến độ sẽ mất khi bạn tải lại trang.
Nội dung theo giấy phép CC BY-NC-SA 4.0. Mã nguồn theo giấy phép MIT.Giới thiệu