Cây quyết định là một chuỗi câu hỏi if-else, ví dụ: điểm bài cơ bản dưới 6 thì vào nhóm làm quen, còn lại thì hỏi tiếp điểm bài khác. Khác với code tự viết, cây tự chọn câu hỏi và ngưỡng từ dữ liệu. Bài này học cách cây chọn câu hỏi ở mỗi nút, và cách giới hạn cây để nó không học thuộc dữ liệu train.
Cấu trúc
Mỗi nút trong hỏi một câu dạng (“tuổi ?”, “số lần đăng nhập ?”). Trả lời có thì đi nhánh trái, không thì đi nhánh phải. Đi từ nút gốc xuống tới nút lá, nơi không còn câu hỏi nào. Mỗi lá chứa một dự đoán: lớp chiếm đa số (phân loại) hoặc giá trị trung bình (hồi quy) của các mẫu train rơi vào lá đó.
Về hình học, cây chia không gian đặc trưng thành các hộp chữ nhật có cạnh song song với trục, mỗi hộp một dự đoán.
Hỏi nhanh
Hai lớp được tách đúng bởi đường chéo . Cây quyết định chỉ dùng phép chia dạng thì biểu diễn ranh giới này thế nào?
Mỗi phép chia chỉ so một feature với một hằng số, nên không có câu hỏi kiểu . Cây xấp xỉ đường chéo bằng những bậc thang, càng sát thì càng cần nhiều nút. Tạo thêm feature thì một phép chia là đủ.
Thế nào là một câu hỏi tốt
Câu hỏi tốt tạo ra các nhóm con thuần (pure): gần như toàn một lớp. Độ “lẫn lộn” của một nút với tỉ lệ các lớp được đo bằng
Cả hai bằng 0 khi nút thuần và lớn nhất khi các lớp chia đều. Gini là xác suất đoán sai nếu gán nhãn ngẫu nhiên theo đúng tỉ lệ trong nút; entropy là lượng thông tin, tính bằng bit, cần để biết nhãn. Trong thực tế hai cách cho cây gần như giống nhau; Gini tính nhanh hơn vì không có log.
Ví dụ:
- Nút có 4 mẫu “Đạt”, 2 mẫu “Trượt”: entropy là bit. (Dùng log tự nhiên thì ra , sai đơn vị.)
- Ba lớp với số mẫu 6, 2, 2: Gini .
Một phép chia đưa nút cha có mẫu thành hai con và mẫu. Độ giảm tạp chất (impurity decrease) của phép chia là
Với entropy, được gọi là information gain. Với hồi quy, thay bằng phương sai của trong nút: chia tốt là chia sao cho mỗi bên có đồng đều.
Hỏi nhanh
Một nút có 3 mẫu lớp 0 và 1 mẫu lớp 1. Gini của nút bằng bao nhiêu?
. là tỉ lệ của lớp ít hơn. là Gini lớn nhất có thể với hai lớp, khi hai lớp chia đều.
Giờ dùng Gini để so hai cách chia. Nút cha có 5 mẫu dương và 5 mẫu âm, nên :
| Cách chia | Trái | Phải | Gini trái | Gini phải | Gini có trọng số | |
|---|---|---|---|---|---|---|
| A | 4+, 1− | 1+, 4− | 0.32 | 0.32 | 0.32 | 0.18 |
| B | 5+, 3− | 0+, 2− | 0.469 | 0 | 0.375 | 0.125 |
Cách B tạo được một nút hoàn toàn thuần, trông hấp dẫn, nhưng nút đó chỉ có 2 mẫu và nút còn lại vẫn rất lộn xộn. Cách A tốt hơn. Dùng entropy cũng ra cùng kết luận: gain của A là 0.278, của B là 0.236.
Huấn luyện: tham lam từng bước
Tìm cây tối ưu toàn cục là bài toán NP-khó. Thuật toán CART dùng chiến lược tham lam: ở mỗi nút, thử mọi đặc trưng và mọi ngưỡng, chọn phép chia có lớn nhất, rồi đệ quy xuống hai con.
Với một đặc trưng, sắp các mẫu theo giá trị rồi chỉ cần thử ngưỡng nằm giữa hai giá trị liên tiếp. Duyệt từ trái sang phải và cập nhật số đếm từng lớp bằng tiền tố, mỗi ngưỡng tính trong . Tổng chi phí cho một nút là , chủ yếu do sắp xếp. Histogram gradient boosting (bài 2.7) gom giá trị vào khoảng 256 thùng để chỉ phải thử vài trăm ngưỡng; DecisionTreeClassifier thông thường thì thử mọi ngưỡng giữa các giá trị khác nhau.
Hỏi nhanh
Một feature có 1000 mẫu nhưng chỉ có 7 giá trị khác nhau, là các điểm từ 4 đến 10. Ở một nút chứa đủ cả 7 giá trị, CART cần thử bao nhiêu ngưỡng cho feature này?
Chỉ cần đặt ngưỡng giữa hai giá trị liên tiếp khác nhau, mà 7 giá trị thì có 6 khoảng. Mọi ngưỡng khác nằm trong cùng một khoảng đều chia mẫu y hệt nhau.
Khi nào dừng
Khi không có hồ sơ đặc trưng trùng nhau mang nhãn mâu thuẫn và không có ràng buộc dừng, cây có thể mọc tới các lá thuần, lỗi train bằng 0, và cây thuộc lòng cả nhiễu. Các cách hãm:
max_depth: giới hạn độ sâu.min_samples_leaf: mỗi lá phải có ít nhất bấy nhiêu mẫu. Thường là tham số hiệu quả nhất. Nó chặn luôn số lá: 100 mẫu vớimin_samples_leaf=20thì cây có nhiều nhất 5 lá.min_impurity_decrease: không chia nếu lợi ích quá nhỏ.- Cắt tỉa (pruning): mọc cây đầy đủ rồi cắt bớt nhánh. Cost-complexity pruning cực tiểu , cũng là kiểu “lỗi + phạt” quen thuộc ở bài 2.2.
Hỏi nhanh
Cost-complexity pruning chọn cây con có nhỏ nhất. Tăng thì cây sau khi tỉa thay đổi thế nào?
Mỗi lá tốn thêm , nên lớn thì chỉ giữ lại những nhánh giảm lỗi đủ nhiều. Cây nhỏ đi thì lỗi train tăng hoặc giữ nguyên. cũng là hyperparameter, chọn bằng validation giống ở bài 2.2.
Điểm mạnh, điểm yếu
Mạnh
- Không cần chuẩn hóa đặc trưng: câu hỏi không quan tâm đơn vị đo. Đổi đơn vị hay lấy log một cột chỉ dời ngưỡng, vì thứ tự các giá trị giữ nguyên; cách chia các mẫu không đổi.
- Tự bắt được quan hệ phi tuyến và tương tác giữa các đặc trưng.
- Đọc được như một bộ luật; dễ giải thích cho người không học máy.
Yếu
- Variance rất cao: đổi vài mẫu train là cây có thể khác hẳn từ gốc.
- Ranh giới chỉ gồm các đoạn song song với trục; một đường chéo đơn giản phải xấp xỉ bằng hình bậc thang. Biết trước ranh giới là thì thêm cột , một câu hỏi là đủ.
- Dự đoán là hằng số từng khúc, nên không ngoại suy: giá trị vượt quá vùng train vẫn chỉ nhận giá trị của lá ngoài cùng.
Chính điểm yếu thứ nhất là lý do người ta ít dùng một cây đơn lẻ, mà gộp nhiều cây lại ở bài 2.6 và 2.7.
Hỏi nhanh
Bỏ ngẫu nhiên 5 trong 500 mẫu train rồi học lại. Cây sâu đổi hẳn phép chia ở gốc, và dự đoán trên validation thay đổi nhiều. Điều này cho thấy gì?
Cây chọn phép chia theo kiểu tham lam, nên một thay đổi nhỏ ở gốc lan xuống cả cây. Đó là variance. Lấy trung bình nhiều cây học trên các mẫu khác nhau sẽ giảm đúng phần này (bài 2.6). Cây không cần chuẩn hóa.
Độ quan trọng đặc trưng
Muốn biết đặc trưng nào quan trọng, có hai cách:
- Impurity importance: cộng dồn (có trọng số theo số mẫu) của mọi phép chia dùng đặc trưng . Cách này nhanh nhưng thiên vị các đặc trưng có nhiều giá trị khác nhau, như ID hay số thực. Cực đoan nhất là cột mã học sinh, mỗi mẫu một giá trị: chia theo nó cho toàn lá thuần, information gain tối đa mà chẳng học được gì. (Thuật toán C4.5 chia gain cho entropy của chính phép chia, gọi là gain ratio, để hãm chuyện này.)
- Permutation importance: xáo trộn cột trên tập validation rồi đo điểm giảm bao nhiêu. Cách này đáng tin hơn.
Hỏi nhanh
Lỡ để cột row_id trong feature, mỗi dòng một số khác nhau. Cây sâu cho cột này impurity importance cao, nhưng permutation importance trên validation thì gần bằng 0. Hiểu thế nào?
Cột có nhiều giá trị khác nhau cho vô số ngưỡng để tách riêng từng mẫu, nên gom được nhiều mức giảm impurity trên train. Trên validation, row_id không mang thông tin gì, nên xáo trộn nó cũng không làm điểm giảm. Bỏ cột này đi rồi kiểm lại.
Cài một nút trước khi cài cả cây
Ta bắt đầu nhỏ hơn CART đầy đủ: chỉ một đặc trưng, một phép chia, gọi là decision stump. Bốn điểm có tọa độ 1, 2, 3, 4 và nhãn 0, 0, 1, 1. Nút gốc có hai lớp ngang nhau nên Gini bằng . Chia ở 2.5 tạo hai lá thuần, Gini sau chia bằng 0; mức giảm là 0.5.
Điểm đáng chú ý là Gini sau chia phải lấy trung bình có trọng số số mẫu. Một lá có 1 mẫu và một lá có 99 mẫu không thể có tiếng nói ngang nhau. Ta chỉ xét ngưỡng giữa hai giá trị liên tiếp khác nhau: trong khoảng đó không điểm nào đổi bên nên xét thêm cũng vô ích.
import numpy as np
def gini(labels):
counts = np.bincount(labels, minlength=2)
probabilities = counts / len(labels)
return 1.0 - np.sum(probabilities ** 2)
x_small = np.array([1., 2., 3., 4.])
y_small = np.array([0, 0, 1, 1])
best = None
for threshold in [1.5, 2.5, 3.5]:
left = x_small <= threshold
right = ~left
after = left.mean() * gini(y_small[left]) + right.mean() * gini(y_small[right])
gain = gini(y_small) - after
print(threshold, round(float(gain), 3))
if best is None or gain > best[0]:
best = (gain, threshold)
print("ngưỡng:", best[1])
assert best[1] == 2.5
1.5 0.167
2.5 0.5
3.5 0.167
ngưỡng: 2.5
Đọc cột gain: ngưỡng 2.5 thắng hai ngưỡng còn lại, dù cả ba đều chia được dữ liệu thành hai phần. Cài cả cây là lặp lại việc này cho từng nút bằng đệ quy, dừng khi lá đủ thuần, quá ít mẫu hoặc đạt độ sâu. Khi nhiều phép chia hòa gain, cần quy tắc phá hòa. Bản nhỏ trên giữ ngưỡng gặp trước; thư viện có quy tắc và ngẫu nhiên riêng nên không được đòi mọi cây giống hệt nhau.
Hỏi nhanh
Sau một phép chia, lá trái có 2 mẫu với Gini bằng 0, lá phải có 18 mẫu với Gini bằng 0.5. Gini có trọng số sau khi chia bằng bao nhiêu?
. Lấy trung bình đều của hai lá thì ra , coi lá nhỏ quan trọng quá mức.
Vì sao tham lam có giới hạn
Decision tree tìm phép chia tốt nhất ngay ở nút hiện tại, không thử mọi cây tương lai. Một ví dụ là XOR: hai bit đầu vào 00, 01, 10, 11 có nhãn 0, 1, 1, 0. Chia theo bit nào ở gốc cũng có gain 0, nhưng chia thêm ở tầng sau thì phân loại được hết. Nếu đặt điều kiện chỉ chia khi gain dương rõ rệt, cây có thể bỏ lỡ tương tác này. Câu “cây tự học mọi tương tác” vì vậy cần hiểu là khả năng biểu diễn, chưa bảo đảm thuật toán tham lam sẽ tìm ra.
Hỏi nhanh
Bốn điểm XOR: , , , . Ở gốc, chia theo thì Gini giảm được bao nhiêu?
Gốc có Gini . Sau khi chia theo , mỗi lá vẫn có một mẫu lớp 0 và một mẫu lớp 1, Gini vẫn là . Trung bình có trọng số bằng , nên mức giảm là 0. Chia theo cũng vậy. Phải sang tầng sau thì mỗi phép chia mới tách hết được.
Đối với hồi quy, một lá dự đoán trung bình nhãn các mẫu train rơi vào lá đó. Dự đoán luôn ở trong khoảng các nhãn lá, nên đưa ra xa vùng train cũng chỉ nhận cùng một giá trị ở lá ngoài cùng. Đây là lý do cây không kéo dài xu hướng như linear regression. Nếu bài có giá trị tương lai vượt xa lịch sử, hãy kiểm ngoại suy trên validation có cấu trúc tương tự, thay vì chỉ random split.
Dùng thư viện
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier, export_text
X, y = load_breast_cancer(return_X_y=True)
for depth in [1, 3, 5, None]:
tree = DecisionTreeClassifier(max_depth=depth, random_state=0)
print(depth, round(cross_val_score(tree, X, y, cv=5).mean(), 3))
tree = DecisionTreeClassifier(max_depth=2, random_state=0).fit(X, y)
print(export_text(tree, feature_names=list(load_breast_cancer().feature_names)))
1 0.9
3 0.917
5 0.916
None 0.917
|--- worst radius <= 16.80
| |--- worst concave points <= 0.14
| | |--- class: 1
| |--- worst concave points > 0.14
| | |--- class: 0
|--- worst radius > 16.80
| |--- worst texture <= 19.91
| | |--- class: 1
| |--- worst texture > 19.91
| | |--- class: 0
Đọc cột CV: sâu 3 đạt 0.917, không giới hạn độ sâu cũng 0.917. Cây sâu 3 nông hơn, đọc được thành một bộ luật ngắn, nên là lựa chọn tự nhiên khi điểm ngang nhau.
Hỏi nhanh
Cross-validation cho độ sâu 1, 3, 5 và không giới hạn lần lượt được 0.900, 0.917, 0.916 và 0.917. Ta nên chọn gì, vì sao?
Chênh lệch 0.001 giữa ba cấu hình nhỏ hơn nhiều so với mức dao động giữa các fold. Khi điểm ngang nhau, cây nông dễ đọc, chạy nhanh và ít nhạy với nhiễu hơn. Độ sâu 1 thì thua rõ, hơn một điểm phần trăm.
Khi đi thi
- Huấn luyện một cây nông, độ sâu 2-4, để xem cột nào quan trọng. Cây độ sâu 1 mà đạt 99% thì nghi có cột lộ đáp án.
- Đề yêu cầu tự cài cây thì đọc kỹ quy ước:
<=hay<, phá hòa giữa các ngưỡng. - Test nằm ở tương lai thì nhớ cây không ngoại suy.
Tóm tắt
- Cây hỏi liên tiếp các câu , chia không gian thành hộp, mỗi hộp một dự đoán.
- Chọn phép chia làm giảm tạp chất (Gini, entropy, phương sai) nhiều nhất; huấn luyện tham lam theo CART.
- Cây sâu thì overfit; hãm bằng độ sâu, số mẫu ở lá, hoặc cắt tỉa.
- Không cần chuẩn hóa, bắt được phi tuyến, nhưng variance cao và không ngoại suy.
Kiểm tra cuối bài
Mười câu kiểm cả cách hiểu, phép tính và quy trình. Câu sai chỉ ra phần cần đọc lại; hãy làm trước khi mở lời giải.
Câu 1
Một nút có 10 mẫu thuộc ba lớp, lần lượt 5, 3 và 2 mẫu. Gini impurity bằng bao nhiêu?
. là tổng các bình phương, quên lấy 1 trừ đi. là Gini lớn nhất với ba lớp, khi ba lớp chia đều.
Câu 2
Trên cùng tập train , ta học hai cây. Một cây chọn phép chia theo information gain, cây kia theo tỉ lệ lỗi trên train. Cả hai đều mọc cho tới khi lỗi train bằng 0. Điều nào chắc chắn đúng?
Lỗi train bằng 0 nghĩa là cả hai cây đều trả đúng nhãn cho mọi mẫu train, nên dự đoán trên trùng nhau. Tiêu chí chia khác nhau có thể chọn gốc khác, độ sâu khác, và bỏ qua những feature khác nhau. Trên dữ liệu mới, hai cây cũng có thể cho kết quả khác nhau.
Phỏng theoCMU 10-601 · Exam 1 Practice · Q1.2
Câu 3
Một lá của cây hồi quy có target là 2, 4 và 9. Hằng số dự đoán nào làm MSE trên lá này nhỏ nhất?
Trung bình làm tổng bình phương sai số nhỏ nhất. Còn 4 là median, làm MAE nhỏ nhất.
Câu 4
Thuật toán học cây kiểu ID3 hay CART có bảo đảm tìm ra cây đạt lỗi train 0 với ít phép chia nhất không?
Thử mọi phép chia tại một nút khác với thử mọi cây có thể có. Ví dụ XOR cho thấy phép chia tốt nhất trước mắt chưa chắc dẫn tới cây gọn nhất. Tìm cây tối ưu toàn cục là bài toán NP-khó. Còn cây không bị giới hạn thì thường đạt lỗi train 0, trừ khi có hai mẫu giống hệt nhau mà khác nhãn.
Phỏng theoCMU 10-601 · Exam 1 Practice · Q1.3
Câu 5
Dữ liệu dự đoán khách bỏ dịch vụ có 10 000 mẫu và 20 feature. Có 15% số ô bị thiếu, rải ngẫu nhiên. Trong bốn đề xuất sau, lập luận nào chính xác nhất?
Nhiều thư viện cây hiện đại học xem tại mỗi phép chia nên đưa ô thiếu sang nhánh nào. Cây quyết định của scikit-learn làm được việc này từ bản 1.3. Bỏ mẫu bị thiếu thì chỉ còn khoảng số mẫu có đủ 20 ô. Điền bằng trung bình chỉ là một baseline, không phải cách tối ưu. Điền theo dòng phía trên chỉ có nghĩa khi các dòng là một chuỗi thời gian.
Câu 6
Cây đúng 100% trên train, 68% trên validation, và cách chia dữ liệu đã được kiểm. Thí nghiệm nào kiểm trực tiếp giả thuyết “cây quá linh hoạt”?
Giảm độ sâu hay tăng số mẫu tối thiểu ở lá đều hạn chế độ phức tạp của cây. Giữ nguyên các fold thì mới so đúng tác động của thay đổi. Có cải thiện hay không thì phải đo mới biết.
Phỏng theoCMU 10-601 · Exam 1 Practice · Q3.1
Câu 7
Một nút hồi quy có target , được chia thành và . Phương sai giảm được bao nhiêu, tính theo trung bình có trọng số?
Nút cha có trung bình , phương sai . Mỗi nút con có phương sai , nên trung bình có trọng số là . Mức giảm là . Ra là lấy phương sai của cha mà quên trừ phần còn lại.
Câu 8
Một cây chỉ sâu 1, tức chỉ có một phép chia, mà đúng 99% trên validation của một đề tưởng là khó. Ta nên nghĩ đến điều gì trước tiên?
Một câu hỏi duy nhất mà gần như đúng hết thường là dấu hiệu rò rỉ: cột ấy được tạo ra sau sự kiện, hoặc mã hóa thẳng nhãn. Hãy đọc feature và ngưỡng ở gốc, rồi hỏi xem lúc dự đoán thật cột ấy đã có chưa (bài 1.4).
Câu 9
Cây hồi quy thông thường dự đoán trung bình ở mỗi lá, và y_train nằm trong khoảng . Với một nằm ngoài vùng train, điều gì đúng?
Cây vẫn đưa vào một lá có sẵn, và trung bình target trong lá luôn nằm giữa giá trị nhỏ nhất và lớn nhất của train. Chưa biết nằm lệch về phía nào thì cũng chưa biết nó rơi vào lá nào.
Câu 10
Feature importance cao có chứng minh được cột ấy gây ra target không?
Importance mô tả mô hình dựa vào cột nào trên dữ liệu này. Nó không nói được chuyện gì xảy ra khi ta can thiệp vào cột ấy. Hai cột tương quan với nhau còn có thể chia importance cho nhau một cách tùy ý.
Đọc thêm
- James, Witten, Hastie, Tibshirani - An Introduction to Statistical Learning, chương 8. Cây, cắt tỉa và cầu nối sang bagging, random forest, boosting.
- Géron - Hands-On Machine Learning, chương 6. Thực hành decision tree với scikit-learn, kèm phần về độ bất ổn của cây.
- scikit-learn - Decision Trees. Đọc thuật toán CART, criterion, giới hạn độ sâu và ví dụ diễn giải cây.
- ISLP - Tree-based methods lab. Thực hành cây, pruning và đối chiếu với ensemble.