ml/ library Learn by doing
ALGORITHM 04 · PYTHON / JAVASCRIPT

Naive Bayes

รวมหลักฐานด้วยกฎของเบย์

LEARNING LEVEL1
พื้นฐานควรรู้มาก่อน · ความน่าจะเป็นพื้นฐาน
ลองใน Playground

01Overall Concept

OVERALL CONCEPT

ไอเดียหลัก — Naive Bayes เป็นนักสืบที่รวมเบาะแสหลายชิ้นเพื่อเดาคำตอบ แต่สมมติแบบง่ายว่าเมื่อรู้กลุ่มแล้ว เบาะแสแต่ละชิ้นไม่เกี่ยวกันมากนัก แม้สมมตินี้จะไม่จริงเสมอ วิธีนี้ก็มักทำงานได้ดีและรวดเร็วกับข้อความ

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

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

02อธิบายภาษาคนเข้าใจง่ายๆ

เล่าแบบไม่ใช้ศัพท์ยาก

Naive Bayes ทำงานคล้ายคนกำลังสืบคดี

สมมติเราเห็น Email หนึ่งฉบับ มีคำว่า

FREE WINNER PROMOTION CLICK NOW

เราก็เริ่มคิดว่า

ดูทรงแล้วน่าจะ Spam

Naive Bayes ก็คิดคล้ายกัน

มันดูว่าในอดีต Email ที่เป็น Spam มักมีคำอะไรบ้าง และ Email ปกติมักมีคำอะไรบ้าง

พอเจอ Email ใหม่มันจะคำนวณว่า

จากหลักฐานทั้งหมด โอกาสเป็น Spam เท่าไร?

คำว่า Naive มาจากสมมติฐานค่อนข้างง่ายว่าหลักฐานแต่ละอย่างเป็นอิสระจากกัน ทั้งที่โลกจริงไม่จำเป็นต้องเป็นแบบนั้น

ฟังดูเหมือนข้อเสียใหญ่ แต่แปลกตรงที่ในหลายงานมันกลับทำงานดีมาก โดยเฉพาะ Text Classification

ข้อดีอีกอย่างคือเร็วมาก ใช้ข้อมูลไม่มาก และเหมาะเป็น Baseline Model

ภาพจำ: นักสืบที่ดูหลักฐานหลายชิ้นแล้วถามว่า “รวมๆ แล้วคดีนี้น่าจะเป็นอะไรที่สุด?”

03How it works

ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ

  1. ต่อจากนักสืบอีเมล แต่เลือกเครื่องมือให้ตรงข้อมูล

    ถ้าจะทำ Spam ให้ X เริ่มเป็นข้อความอีเมล และ y เป็น spam/normal จากนั้นแปลงข้อความเป็นจำนวนคำด้วย CountVectorizer แล้วใช้ MultinomialNB ส่วนโค้ดและ Playground ในหน้านี้ใช้ GaussianNB กับข้อมูลตัวเลขต่อเนื่อง เช่นขนาดกลีบดอกไม้ จึงต้องแยกสองรุ่นนี้ให้ชัดก่อนลงมือ

  2. หลักฐานตัวเลขถูกสรุปอย่างไร

    สำหรับ GaussianNB เริ่มด้วย X เป็นตารางความยาวและความกว้างกลีบ y เป็นชนิดดอกไม้ แบ่งชุดทดสอบแบบ stratify=y ตอน fit โมเดลนับสัดส่วนแต่ละคลาสเป็น prior และเก็บค่าเฉลี่ยกับความแปรปรวนของแต่ละ feature ภายในแต่ละคลาส เหมือนจดว่าดอกไม้ชนิดนี้มักมีขนาดประมาณไหน

  3. เอาหลักฐานมารวมคะแนน

    เมื่อเจอดอกใหม่ โมเดลประเมินว่าค่ากลีบแต่ละค่าพบบ่อยแค่ไหนในแต่ละชนิด แล้วรวมกับ prior สมมติฐานสำคัญคือ feature เป็นอิสระต่อกันเมื่อรู้คลาส ในทางคำนวณนิยมบวกคะแนน log เพื่อลดปัญหาคูณเลขเล็กๆ จนใกล้ศูนย์ สุดท้ายเปลี่ยนคะแนนรวมเป็นความน่าจะเป็นของทุกคลาส

  4. ฝึกและเลือกปุ่มให้ตรงรุ่น

    GaussianNB(var_smoothing=1e-9).fit(X_train, y_train) เป็นจุดเริ่มได้ var_smoothing เติมความแปรปรวนเล็กน้อยเพื่อไม่ให้คำนวณมั่นใจเกินไปเมื่อคอลัมน์แทบไม่เปลี่ยน ค่า priors ใช้กำหนดสัดส่วนคลาสล่วงหน้าถ้ามีเหตุผล ส่วนงานข้อความใช้ make_pipeline(CountVectorizer(), MultinomialNB(alpha=1.0)) โดย alpha เป็นการเผื่อคำที่ยังไม่เคยพบ

  5. ลองของใหม่และดูข้อผิดพลาด

    predict ให้ชนิดที่คะแนนสูงสุด ส่วน predict_proba ให้คะแนนความน่าจะเป็น แต่ Naive Bayes อาจมั่นใจเกินจริงได้ ตรวจ confusion matrix และ precision/recall แยกแต่ละคลาส สำหรับข้อความให้ fit ตัว vectorizer เฉพาะชุดฝึก เพื่อไม่ให้คำศัพท์จากชุดทดสอบรั่วเข้ามา แล้วอ่านตัวอย่างที่จำแนกผิดเพื่อปรับการเตรียมข้อความ

เปิดตัวอย่างโค้ดเพื่อลองทำตาม →ตัวอย่างตัวเลขในเรื่องใช้ช่วยอธิบาย ส่วนโค้ดและ Playground ใช้ชุดข้อมูลสาธิตของแต่ละหน้าอ่านเอกสารอ้างอิงของเทคนิคนี้ ↗

ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ

DATA INX · featuresy · targetGaussianNB: X = [ความยาวกลีบ, ความกว้างกลีบ] · y = ชนิดดอกไม้
CALCULATENaive Bayes
priorsvar_smoothingsample_weight
RESULT0.800.150.05class / probabilitypredict → ชนิดดอกไม้ · งานข้อความให้เปลี่ยนเป็น MultinomialNB
เส้นทางของข้อมูล: จากค่าที่รับเข้า ผ่านการคำนวณด้วยพารามิเตอร์ ไปเป็นผลลัพธ์
INPUT

ข้อมูลที่รับเข้ามา

รับ X เป็นค่าของหลักฐานแต่ละข้อและ y เป็นป้ายคลาส รูปแบบ X ขึ้นกับรุ่นย่อย เช่น GaussianNB รับตัวเลขต่อเนื่อง

GaussianNB: X = [ความยาวกลีบ, ความกว้างกลีบ] · y = ชนิดดอกไม้
PARAMETERS

พารามิเตอร์ที่ใช้

priors
โอกาสเริ่มต้นของแต่ละคลาส ถ้าไม่ใส่จะเรียนรู้จากข้อมูล
var_smoothing
ค่าบวกเล็ก ๆ ที่ช่วยให้การคำนวณ variance ไม่เป็นศูนย์
sample_weight
น้ำหนักความสำคัญของแต่ละตัวอย่างระหว่าง fit
OUTPUT

ผลลัพธ์ที่ได้

ได้คะแนน posterior probability ของทุกคลาสและป้ายคลาสที่มีคะแนนสูงสุด

predict → ชนิดดอกไม้ · งานข้อความให้เปลี่ยนเป็น MultinomialNB
CALCULATION

คำนวณทีละขั้น

  1. 01

    นับ prior P(class) และเรียนรู้ distribution ของแต่ละ feature ภายในแต่ละคลาส

  2. 02

    คำนวณ likelihood P(feature|class) ของหลักฐานทุกตัว โดยสมมติว่าแยกจากกันเมื่อรู้คลาส

  3. 03

    รวมคะแนนตามกฎ Bayes แล้ว normalize เป็น probability ก่อนเลือกคลาสที่สูงที่สุด

ควรรู้อีกนิด — สมมติฐานอิสระมักไม่จริง ทำให้ probability มั่นใจเกิน แต่การจัดคลาสยังอาจทำงานได้ดี

04Make it yours

Python · scikit-learn
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.naive_bayes import GaussianNBfrom sklearn.metrics import accuracy_score from sklearn.datasets import make_classificationfrom sklearn.model_selection import train_test_split X, y = make_classification(    n_samples=150, n_features=2, n_redundant=0,    n_informative=2, n_classes=3, n_clusters_per_class=1,    class_sep=1.4, random_state=42,)X_train, X_test, y_train, y_test = train_test_split(    X, y, test_size=0.2, random_state=42, stratify=y) model = GaussianNB(var_smoothing=0.10)model.fit(X_train, y_train)pred = model.predict(X_test)print("Accuracy:", accuracy_score(y_test, pred))

โค้ดเปลี่ยนตามค่าที่เลือกใน Playground · แต่ละภาษาใช้ข้อมูลตัวอย่างตามที่ระบุในโค้ด

05Learn by playing

ปรับ variance smoothing แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที

Sample dataset / Word counts · Three classes● คำนวณใหม่เมื่อปรับค่า
เพิ่มความนุ่มให้ distribution และลดความมั่นใจสุดขั้ว
พื้นที่สีคือคำทำนาย จุดคือคำตอบจริงFeature x → · Feature y ↑ · ขอบเข้ม = ชุดทดสอบ
Test accuracy93.3%
ชุดทดสอบ30 จุด
พารามิเตอร์ที่ลอง0.10

Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง