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

ในหน่วยการเรียนรู้นี้ คุณจะได้ใช้ไลบรารี 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 นี้ใช้ชุดข้อมูล นกเพนกวินของ Palmer ซึ่งมีข้อมูลการวัดขนาดของนกเพนกวิน 3 สายพันธุ์

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

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

นกเพนกวิน 3 สายพันธุ์
ที่แตกต่างกัน

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

 

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

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 รองรับฟีเจอร์ประเภทเหล่านี้ทั้งหมดโดยกำเนิด คุณจึงไม่ต้องทำการเข้ารหัสแบบ One-Hot, การทำให้เป็นมาตรฐาน หรือฟีเจอร์ 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 คุณสามารถใช้เมาส์เพื่อแสดงรายละเอียดเกี่ยวกับองค์ประกอบที่เฉพาะเจาะจง เช่น การกระจายคลาสในแต่ละโหนด

Decision Tree ที่ฝึกด้วยไฮเปอร์พารามิเตอร์เริ่มต้น

รูปที่ 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 จึงได้มาจากการใช้อัลกอริทึมการแยกที่แน่นอนสำหรับการจัดประเภทแบบไบนารีที่มีฟีเจอร์เชิงตัวเลข

หาก bill_depth_mm ≥ 42.3 เป็นจริง ให้ทดสอบเพิ่มเติมว่า flipper_length_mm ≥ 207.5 สามารถแยก นกเพนกวินเจนตูออกจากนกเพนกวินเจนตูและนกเพนกวินอะเดลีได้เกือบสมบูรณ์หรือไม่

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

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. ใช้เครื่องมือการเรียนรู้ที่มีประสิทธิภาพมากขึ้น เช่น โมเดลป่าสุ่ม หรือต้นไม้ที่เพิ่มประสิทธิภาพด้วยการไล่ระดับสี เราจะอธิบายอัลกอริทึมการเรียนรู้เหล่านั้นในหน้าถัดไป

  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 การเปลี่ยนแปลงไฮเปอร์พารามิเตอร์นี้เป็นความคิดที่ดี

ตัวอย่าง Decision Forest

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

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

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

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

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

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