การสร้างแผนผังการตัดสินใจ

ในหน่วยนี้ คุณจะใช้คลัง YDF (Yggdrasil Decision Forest) เพื่อฝึกและตีความแผนผังการตัดสินใจ

หน่วยการเรียนรู้นี้ได้รับแรงบันดาลใจจากบทแนะนำ🧭การเริ่มต้นใช้งาน YDF

รอบคัดเลือก

ก่อนศึกษาชุดข้อมูล ให้ทําดังนี้

  1. สร้าง Colab Notebook ใหม่
  2. ติดตั้งไลบรารี YDF โดยวางและเรียกใช้บรรทัดโค้ดต่อไปนี้ในสมุดบันทึก Colab ใหม่
    !pip install ydf -U
  3. นําเข้าไลบรารีต่อไปนี้
    import ydf
    import numpy as np
    import pandas as pd

ชุดข้อมูลเพนกวินพาล์มเมอร์

Colab นี้ใช้ชุดข้อมูล Penguins ของ Palmer ซึ่งมีข้อมูลการวัดขนาดของนกเพนกวิน 3 สายพันธุ์ ดังนี้

  • สายรัดคาง
  • Gentoo
  • Adelie

นี่เป็นปัญหาการจัดประเภท โดยมีเป้าหมายเพื่อคาดการณ์สายพันธุ์นกเพนกวินตามข้อมูลในชุดข้อมูลนกเพนกวินของ Palmer เพนกวินมีดังนี้

นกเพนกวิน 3 สายพันธุ์

รูปที่ 16 นกเพนกวิน 3 สายพันธุ์ รูปภาพโดย @allisonhorst

 

โค้ดต่อไปนี้จะเรียกใช้ฟังก์ชัน pandas เพื่อโหลดชุดข้อมูล Palmer Penguins ลงในหน่วยความจํา

path = "https://storage.googleapis.com/download.tensorflow.org/data/palmer_penguins/penguins.csv"
dataset = pd.read_csv(path)
label = "species"

# Display the first 3 examples.
dataset.head(3)

ตารางต่อไปนี้จัดรูปแบบตัวอย่าง 3 รายการแรกในชุดข้อมูล Palmer Penguins

ตารางที่ 3 ตัวอย่าง 3 รายการแรกใน Palmer Penguins

ชนิดพันธุ์ เกาะ bill_length_mm bill_depth_mm flipper_length_mm body_mass_g เพศ ปี
0 Adelie Torgersen 39.1 18.7 181.0 3750.0 ชาย 2007
1 Adelie Torgersen 39.5 17.4 186.0 3800.0 เป็นเพศหญิง 2007
2 Adelie Torgersen 40.3 18.0 195.0 3250.0 เป็นเพศหญิง 2007

ชุดข้อมูลแบบสมบูรณ์มีทั้งตัวเลข (เช่น bill_depth_mm) หมวดหมู่ (เช่น island) และฟีเจอร์ที่ขาดหายไป ต่างจากเครือข่ายประสาท Decision Forest รองรับประเภทฟีเจอร์เหล่านี้ทั้งหมดโดยกำเนิด คุณจึงไม่ต้องทำการเข้ารหัสแบบฮอตเวิร์ก การปรับให้เป็นมาตรฐาน หรือฟีเจอร์ is_present เพิ่มเติม

เซลล์โค้ดต่อไปนี้จะแยกชุดข้อมูลออกเป็นชุดการฝึกและชุดการทดสอบ

# Use the ~20% of the examples as the testing set
# and the remaining ~80% of the examples as the training set.
np.random.seed(1)
is_test = np.random.rand(len(dataset)) < 0.2

train_dataset = dataset[~is_test]
test_dataset = dataset[is_test]

print("Training examples: ", len(train_dataset))
# >> Training examples: 272

print("Testing examples: ", len(test_dataset))
# >> Testing examples: 72

การฝึกต้นไม้การตัดสินใจด้วยไฮเปอร์พารามิเตอร์เริ่มต้น

คุณสามารถฝึกต้นไม้การตัดสินใจต้นแรกด้วยอัลกอริทึมการเรียนรู้ CART (Classification and Regression Trees) (หรือที่เรียกว่าตัวเรียนรู้) โดยไม่ต้องระบุไฮเปอร์พารามิเตอร์ใดๆ นั่นเป็นเพราะ ydf.CartLearner learner ให้ค่าไฮเปอร์พารามิเตอร์เริ่มต้นที่ดี คุณจะได้ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทํางานของรูปแบบนี้ในภายหลัง

model = ydf.CartLearner(label=label).train(train_dataset)

การเรียกก่อนหน้านี้ไม่ได้ระบุคอลัมน์ที่จะใช้เป็นฟีเจอร์อินพุต ดังนั้น ระบบจะใช้ทุกคอลัมน์ในชุดการฝึก นอกจากนี้ การเรียกใช้ดังกล่าวไม่ได้ระบุความหมาย (เช่น ตัวเลข หมวดหมู่ ข้อความ) ของฟีเจอร์อินพุต ระบบจึงจะอนุมานความหมายขององค์ประกอบโดยอัตโนมัติ

เรียกใช้ model.plot_tree() เพื่อแสดงแผนผังการตัดสินใจที่ได้

model.plot_tree()

ใน Colab คุณสามารถใช้เมาส์เพื่อแสดงรายละเอียดเกี่ยวกับองค์ประกอบที่เฉพาะเจาะจง เช่น การแจกแจงคลาสในแต่ละโหนด

แผนผังการตัดสินใจที่ผ่านการฝึกด้วยไฮเปอร์พารามิเตอร์เริ่มต้น

รูปที่ 17 แผนผังการตัดสินใจที่ผ่านการฝึกด้วยไฮเปอร์พารามิเตอร์เริ่มต้น

Colab แสดงว่าเงื่อนไขรูทมีตัวอย่าง 243 รายการ อย่างไรก็ตาม คุณอาจจำได้ว่าชุดข้อมูลการฝึกอบรมมีตัวอย่าง 272 รายการ ระบบได้จองตัวอย่างที่เหลือ 29 รายการไว้โดยอัตโนมัติเพื่อใช้ตรวจสอบและตัดต้นไม้

เงื่อนไขแรกจะทดสอบค่าของ bill_depth_mm ตารางที่ 4 และ 5 แสดงความเป็นไปได้ของสายพันธุ์ต่างๆ โดยขึ้นอยู่กับผลลัพธ์ของเงื่อนไขแรก

ตารางที่ 4 ความน่าจะเป็นที่จะมีสายพันธุ์อื่นหาก bill_depth_mm ≥ 42.3

สายพันธุ์ ความเป็นไปได้
Adelie (สีแดง) 8%
Gentoo (สีน้ำเงิน) 58%
สายรัดคาง (สีเขียว) 36%

 

ตาราง 5 ความเป็นไปได้ที่จะมีสายพันธุ์อื่นหาก bill_depth_mm < 42.3

สายพันธุ์ ความเป็นไปได้
Adelie (สีแดง) 97%
Gentoo (สีน้ำเงิน) 2%
สายรัดคาง (สีเขียว) 0%

bill_depth_mm เป็นองค์ประกอบตัวเลข ดังนั้น ระบบจึงพบค่า 42.3 โดยใช้อัลกอริทึมการแยกที่แน่นอนสำหรับการแยกประเภทแบบ 2 กลุ่มด้วยฟีเจอร์ที่เป็นตัวเลข

หาก bill_depth_mm ≥ 42.3 เป็น True ให้ทดสอบเพิ่มเติมว่า flipper_length_mm ≥ 207.5 แยก Gentoos ออกจาก Gentoos+Adelie ได้เกือบสมบูรณ์แบบหรือไม่

โค้ดต่อไปนี้แสดงความแม่นยำของการฝึกอบรมและทดสอบของโมเดล

train_evaluation = model.evaluate(train_dataset)
print("train accuracy:", train_evaluation.accuracy)
# >> train accuracy:  0.9338

test_evaluation = model.evaluate(test_dataset)
print("test accuracy:", test_evaluation.accuracy)
# >> test accuracy:  0.9167

ความแม่นยำในการทดสอบสูงกว่าความแม่นยำในการฝึกนั้นเกิดขึ้นได้น้อย แต่ก็เป็นไปได้ ในกรณีนี้ ชุดทดสอบอาจแตกต่างจากชุดการฝึก แต่ในกรณีนี้ ไม่ได้เป็นเช่นนั้น เนื่องจากมีการแบ่งกลุ่มทดสอบและกลุ่มควบคุมแบบสุ่ม คำอธิบายที่เป็นไปได้มากกว่าคือชุดข้อมูลทดสอบมีขนาดเล็กมาก (มีเพียง 72 ตัวอย่าง) การประมาณความแม่นยำจึงมีความคลาดเคลื่อน

ในทางปฏิบัติแล้ว สําหรับชุดข้อมูลขนาดเล็กเช่นนี้ เราขอแนะนําให้ใช้การทดสอบไขว้ เนื่องจากจะคํานวณค่าเมตริกการประเมินที่แม่นยํากว่า อย่างไรก็ตาม ในตัวอย่างนี้ เราจะฝึกและทดสอบต่อเพื่อความเรียบง่าย

การปรับปรุงไฮเปอร์พารามิเตอร์ของโมเดล

โมเดลนี้เป็นต้นไม้การตัดสินใจเดียวที่ผ่านการฝึกด้วยค่าไฮเปอร์พารามิเตอร์เริ่มต้น หากต้องการการคาดการณ์ที่ดีขึ้น คุณสามารถทำสิ่งต่อไปนี้

  1. ใช้เครื่องมือเรียนรู้ที่มีประสิทธิภาพมากขึ้น เช่น Random Forest หรือGradient Boosted Trees เราจะอธิบายอัลกอริทึมการเรียนรู้เหล่านั้นในหน้าถัดไป

  2. เพิ่มประสิทธิภาพไฮเปอร์พารามิเตอร์โดยใช้การสังเกตและการคาดคะเน คู่มือการปรับปรุงโมเดลอาจมีประโยชน์

  3. ใช้การปรับแต่งไฮเปอร์พารามิเตอร์เพื่อทดสอบไฮเปอร์พารามิเตอร์ที่เป็นไปได้จํานวนมากโดยอัตโนมัติ

เนื่องจากเรายังไม่เห็นอัลกอริทึมของ Random Forest และ Gradient Boosted Trees และเนื่องจากจำนวนตัวอย่างมีน้อยเกินไปที่จะทำการปรับแต่งไฮเปอร์พารามิเตอร์โดยอัตโนมัติ คุณจึงต้องปรับปรุงโมเดลด้วยตนเอง

แผนภูมิการตัดสินใจที่แสดงด้านบนมีขนาดเล็ก และใบที่มีตัวอย่าง 61 รายการมีป้ายกำกับ Adelie และ Chinstrap ผสมกัน เหตุใดอัลกอริทึมจึงไม่แบ่งกลุ่มใบไม้นี้ย่อยลงไปอีก มีสาเหตุที่เป็นไปได้สองข้อ:

  • อาจมีจำนวนตัวอย่างขั้นต่ำต่อใบ (min_examples=5 โดยค่าเริ่มต้น) แล้ว
  • ระบบอาจแยกและตัดต้นไม้ออกเพื่อป้องกันการพอดีมากเกินไป

ลดจำนวนตัวอย่างขั้นต่ำเป็น 1 และดูผลลัพธ์

model = ydf.CartLearner(label=label, min_examples=1).train(train_dataset)
model.plot_tree()

แผนผังการตัดสินใจที่ผ่านการฝึกด้วย
min_examples=1

รูปที่ 18 แผนผังการตัดสินใจที่ผ่านการฝึกด้วย min_examples=1

 

โหนดใบที่มี 61 ตัวอย่างได้รับการแบ่งย่อยเพิ่มเติมหลายครั้ง

หากต้องการดูว่าการแยกโหนดเพิ่มเติมมีประโยชน์หรือไม่ เราจะประเมินคุณภาพของรูปแบบใหม่นี้ในชุดข้อมูลทดสอบ ดังนี้

print(model.evaluate(test_dataset).accuracy)
# >> 0.97222

คุณภาพของโมเดลเพิ่มขึ้นเมื่อความแม่นยำในการทดสอบเพิ่มขึ้นจาก 0.9167 เป็น 0.97222 การเปลี่ยนแปลงไฮเปอร์พารามิเตอร์นี้ถือเป็นแนวคิดที่ดี

ก่อนหน้านี้ของป่าการตัดสินใจ

การปรับปรุงไฮเปอร์พารามิเตอร์อย่างต่อเนื่องอาจช่วยให้เราบรรลุความแม่นยำที่สมบูรณ์แบบ อย่างไรก็ตาม เราฝึกโมเดลที่มีประสิทธิภาพมากขึ้น เช่น Random Forest และดูว่าได้ผลลัพธ์ที่ดีกว่าไหมแทนที่จะทำด้วยตนเอง

model = ydf.RandomForestLearner(label=label).train(train_dataset)
print("Test accuracy: ", model.evaluate(test_dataset).accuracy)
# >> Test accuracy: 0.986111

ความแม่นยำของ Random Forest ดีกว่าต้นไม้แบบง่าย คุณจะได้ทราบเหตุผลในหน้าถัดไป

การใช้งานและข้อจํากัด

ดังที่ได้กล่าวไว้ก่อนหน้านี้ ต้นไม้การตัดสินใจเดี่ยวมักมีคุณภาพต่ำกว่าวิธีการแมชชีนเลิร์นนิงสมัยใหม่ เช่น Random Forest, Gradient Boosted Tree และโครงข่ายประสาท อย่างไรก็ตาม แผนผังการตัดสินใจยังคงมีประโยชน์ในกรณีต่อไปนี้

  • เป็นฐานข้อมูลที่ง่ายและไม่แพงสําหรับประเมินแนวทางที่ซับซ้อนมากขึ้น
  • เมื่อมีการเลือกระหว่างคุณภาพของโมเดลกับความสามารถในการตีความ
  • เพื่อเป็นตัวแทนในการตีความโมเดลป่าการตัดสินใจ ซึ่งหลักสูตรจะกล่าวถึงในภายหลัง