01 Overall Concept
ไอเดียหลัก — Decision Tree เรียนรู้ด้วยคำถามแบบ “ใช่หรือไม่” ทีละข้อ เช่น ผลไม้นี้สีแดงไหม หรือมีน้ำหนักเกินเท่านี้ไหม ทุกคำตอบพาเราเดินไปคนละกิ่ง จนถึงปลายทางที่บอกคำทำนาย
ลองนึกภาพว่า — เหมือนเล่นเกมทายสัตว์ เราเริ่มด้วยคำถามว่า “อยู่ในน้ำไหม” แล้วถามต่อว่า “มีครีบไหม” คำถามที่ดีจะช่วยตัดตัวเลือกออกได้มากและพาไปถึงคำตอบเร็ว
ตัวอย่างการนำไปใช้ — จำแนกชนิดพืช คัดแยกคำร้องของลูกค้า ประเมินว่าลูกค้าจะกลับมาซื้อหรือไม่ และงานที่ต้องอธิบายเหตุผลเป็นกฎง่าย ๆ
02 อธิบายภาษาคนเข้าใจง่ายๆ
Decision Tree คิดเหมือนคนตัดสินใจตาม Flowchart
สมมติเราจะอนุมัติสินเชื่อ
มันอาจสร้างต้นไม้แบบนี้
รายได้ > 50,000 ไหม?
ถ้าไม่ → ดูหนี้ ถ้าใช่ → ดูประวัติชำระเงิน
แล้วถามต่อไปเรื่อยๆ
เคยผิดนัดไหม? มีงานประจำไหม? หนี้เกิน 40% ของรายได้ไหม?
สุดท้ายไปถึงใบไม้ เช่น
อนุมัติ ไม่อนุมัติ
ข้อดีมากๆ คือมนุษย์เข้าใจง่าย เราสามารถเปิดดูเหตุผลได้แทบเหมือนอ่าน Flowchart
ปัญหาคือ Decision Tree ตัวเดียว “ใจร้อน” พอสมควร
ถ้าข้อมูลเปลี่ยนเล็กน้อย ต้นไม้อาจสร้างโครงสร้างต่างไปมาก และถ้าปล่อยให้แตกกิ่งเยอะเกินไปก็ Overfit ได้ง่าย
นี่เป็นเหตุผลที่ภายหลังเกิดเทคนิคอย่าง Random Forest ขึ้นมา
ภาพจำ: เกม 20 Questions — ถามทีละข้อจนรู้ว่าคำตอบคืออะไร
03 How it works
ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ
เตรียมแฟ้มสินเชื่อที่มีคำตอบเก่า
หนึ่งแถวแทนหนึ่งใบสมัคร X มีรายได้ สัดส่วนหนี้ และประวัติที่ทราบตอนสมัคร ส่วน y เป็นคำตอบเป้าหมาย เช่นผลชำระคืนจริงที่กำหนดช่วงเวลาชัดเจน หากใช้ผลอนุมัติเก่าเป็น y โมเดลจะเรียนแบบการอนุมัติเก่า ไม่ใช่ความเสี่ยงผิดนัดโดยตรง แบ่ง test ก่อนและแปลงหมวดหมู่เป็นตัวเลขให้เหมาะสม
ต้นไม้คิดคำถามแรกเอง
ตอน fit มันลอง feature กับ threshold หลายแบบ เช่นรายได้ ≤ 50,000 แล้วดูว่าซ้ายกับขวาแยกคลาสได้ดีขึ้นแค่ไหน สำหรับ classification วัดด้วย Gini หรือ entropy ซึ่งสะท้อนความปะปนของคลาส คำถามที่ลดความปะปนรวมโดยถ่วงจำนวนคนแต่ละฝั่งได้ดีที่สุดจะถูกเลือก
ถามต่อจนถึงป้ายคำตอบ
ต้นไม้ทำขั้นตอนเดิมกับข้อมูลในแต่ละกิ่ง ถ้าฝั่งหนึ่งยังปนหลายคลาสก็ถามเพิ่ม เมื่อถึงเงื่อนไขหยุดจะเก็บสัดส่วนคลาสไว้ที่ใบ เช่นใบหนึ่งมี 8 คนเป็นคลาส A และ 2 คนเป็น B จะทาย A พร้อมสัดส่วน 0.8 ถ้าเป็น DecisionTreeRegressor เปลี่ยนเป็นลดความผิดพลาดของตัวเลขและใช้ค่าเฉลี่ยที่ใบแทน
ตั้งรั้วไม่ให้แตกกิ่งไม่จบ
เริ่ม DecisionTreeClassifier(max_depth=3, min_samples_leaf=5, random_state=42) แล้ว fit(X_train, y_train) max_depth จำกัดจำนวนชั้นคำถาม min_samples_leaf บังคับให้แต่ละใบมีข้อมูลอย่างน้อยกี่แถว และ criterion เลือกวิธีวัดความปะปน เริ่มจากต้นเล็กจะอ่านกฎและเห็นข้อผิดพลาดง่ายกว่า
เดินตามต้นไม้และตรวจสิ่งที่พลาด
predict(X_test) จะพาแต่ละแถวเดินตามคำถามจนถึงใบ ใช้ plot_tree(model, feature_names=...) เพื่อเปิดดูโครงสร้าง แล้วดู confusion matrix ว่าพลาดคลาสใด ลองเพิ่ม max_depth ทีละระดับใน validation ถ้า train ดีขึ้นแต่ test ไม่ดีขึ้นให้หยุด การนำไปใช้ตัดสินสินเชื่อจริงยังต้องตรวจคุณภาพข้อมูลและกฎงาน เพราะโมเดลอาจจำความลำเอียงจากคำตอบเก่า
ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ
max_depthmin_samples_leafcriterionข้อมูลที่รับเข้ามา
รับ X เป็นตารางที่แต่ละคอลัมน์คือคุณลักษณะ และ y เป็นคลาสหรือค่าต่อเนื่อง ตัวเลขและหมวดหมู่ที่เข้ารหัสแล้วใช้เป็นเงื่อนไขแตกกิ่งได้
X = [รายได้, สัดส่วนหนี้, ประวัติ] · y = คลาสเป้าหมายพารามิเตอร์ที่ใช้
- max_depth
- จำนวนชั้นคำถามสูงสุดของต้นไม้
- min_samples_leaf
- จำนวนตัวอย่างขั้นต่ำที่ปลายกิ่งต้องมี
- criterion
- Classifier ใช้ gini หรือ entropy; squared_error เป็นของ Regressor
ผลลัพธ์ที่ได้
ได้โครงสร้างต้นไม้ กฎ if–else และคำทำนายหนึ่งค่าต่อแถว พร้อม probability จากสัดส่วนที่ใบ
ตัวอย่างใบ: A 8 คน, B 2 คน → ทาย A และสัดส่วน 0.8คำนวณทีละขั้น
- 01
ลองทุก feature และ threshold ที่เป็นไปได้เพื่อแบ่งข้อมูลออกเป็นซ้ายกับขวา
- 02
เลือกคำถามที่ลด impurity แบบถ่วงจำนวนตัวอย่างของแต่ละฝั่งได้ดีที่สุด
- 03
ทำซ้ำในแต่ละกิ่งจนชนเงื่อนไขหยุด แล้วเก็บคลาสเสียงข้างมากหรือค่าเฉลี่ยไว้ที่ใบ
ควรรู้อีกนิด —
04 Make it yours
# ติดตั้ง: pip install numpy pandas scikit-learn matplotlibimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.tree import DecisionTreeClassifier, plot_treefrom sklearn.metrics import accuracy_score # ดาวน์โหลด sample.csv จาก Playground ไว้ข้างไฟล์นี้df = pd.read_csv("sample.csv")X, y = df[["x", "y"]], df["label"]is_test = np.arange(len(df)) % 5 == 0 # test 20%, ชุดเดียวกับเว็บ model = DecisionTreeClassifier( max_depth=3, # ความลึกมากขึ้น = กฎที่ละเอียดขึ้น min_samples_leaf=3, # จำนวนตัวอย่างขั้นต่ำในแต่ละใบ criterion="gini", random_state=42,)model.fit(X[~is_test], y[~is_test])pred = model.predict(X[is_test])print("Test accuracy:", accuracy_score(y[is_test], pred))plt.figure(figsize=(16, 8))plot_tree(model, feature_names=["x", "y"], class_names=["Class 1", "Class 2", "Class 3"], filled=True, rounded=True, fontsize=10)plt.tight_layout()plt.show()โค้ดอัปเดตตามพารามิเตอร์ใน Playground ด้านล่าง · เปลี่ยนไฟล์และคอลัมน์เพื่อใช้ข้อมูลของคุณ
05 Learn by playing
ลองปรับความลึก แล้วดูจำนวนกิ่ง เงื่อนไข และคำตอบที่ใบ เปลี่ยนตัวอย่างเพื่อเดินตามเส้นทางการตัดสินใจจริง
อ่านจากบนลงล่าง: ทดสอบเงื่อนไข → เลือกกิ่ง → คำตอบที่ใบ
เลื่อนซ้าย–ขวาเพื่อดูทุกกิ่ง · กรอบและเส้นสีเขียวแสดงเส้นทางของตัวอย่างด้านล่าง · ค่าในภาพปัดเป็นทศนิยม 2 ตำแหน่ง
ตัวอย่างจากชุดทดสอบที่โมเดลไม่เคยใช้ฝึก
- Feature x
- 9.28
- Feature y
- 6.10
- คำตอบจริง
- คลาส 1
- โมเดลทำนาย
- คลาส 1 ✓
- y = 6.10 ≤ 50.12 → ใช่
- x = 9.28 ≤ 50.37 → ใช่
- x = 9.28 ≤ 45.66 → ใช่
- ถึงใบ → คลาส 1
ดูกฎที่ต้นไม้เรียนรู้
y ≤ 50.1 ├ yes: x ≤ 50.4 ├ yes: x ≤ 45.7 ├ yes: กลุ่ม 1 (36 ตัวอย่าง) └ no: กลุ่ม 1 (3 ตัวอย่าง) └ no: กลุ่ม 2 (36 ตัวอย่าง) └ no: y ≤ 57.3 ├ yes: x ≤ 65.5 ├ yes: กลุ่ม 3 (5 ตัวอย่าง) └ no: กลุ่ม 2 (3 ตัวอย่าง) └ no: x ≤ 25.1 ├ yes: กลุ่ม 3 (3 ตัวอย่าง) └ no: กลุ่ม 3 (34 ตัวอย่าง)ข้อมูลสังเคราะห์ 150 จุด มี 2 features และ 3 กลุ่ม ใช้ seed 42 เพื่อให้ทดลองซ้ำได้ แยกทุกจุดลำดับที่ 5 เป็น test set คงที่ 30 จุด; Playground ใช้ CART/Gini แบบย่อ ผลอาจต่างจาก scikit-learn เมื่อมีจุดแบ่งที่คะแนนเท่ากัน ผลนี้ใช้เพื่อเรียนรู้ ไม่ใช่ benchmark บนข้อมูลจริง