01Overall 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
ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ
ต่อจากนักสืบอีเมล แต่เลือกเครื่องมือให้ตรงข้อมูล
ถ้าจะทำ Spam ให้ X เริ่มเป็นข้อความอีเมล และ y เป็น spam/normal จากนั้นแปลงข้อความเป็นจำนวนคำด้วย CountVectorizer แล้วใช้ MultinomialNB ส่วนโค้ดและ Playground ในหน้านี้ใช้ GaussianNB กับข้อมูลตัวเลขต่อเนื่อง เช่นขนาดกลีบดอกไม้ จึงต้องแยกสองรุ่นนี้ให้ชัดก่อนลงมือ
หลักฐานตัวเลขถูกสรุปอย่างไร
สำหรับ GaussianNB เริ่มด้วย X เป็นตารางความยาวและความกว้างกลีบ y เป็นชนิดดอกไม้ แบ่งชุดทดสอบแบบ stratify=y ตอน fit โมเดลนับสัดส่วนแต่ละคลาสเป็น prior และเก็บค่าเฉลี่ยกับความแปรปรวนของแต่ละ feature ภายในแต่ละคลาส เหมือนจดว่าดอกไม้ชนิดนี้มักมีขนาดประมาณไหน
เอาหลักฐานมารวมคะแนน
เมื่อเจอดอกใหม่ โมเดลประเมินว่าค่ากลีบแต่ละค่าพบบ่อยแค่ไหนในแต่ละชนิด แล้วรวมกับ prior สมมติฐานสำคัญคือ feature เป็นอิสระต่อกันเมื่อรู้คลาส ในทางคำนวณนิยมบวกคะแนน log เพื่อลดปัญหาคูณเลขเล็กๆ จนใกล้ศูนย์ สุดท้ายเปลี่ยนคะแนนรวมเป็นความน่าจะเป็นของทุกคลาส
ฝึกและเลือกปุ่มให้ตรงรุ่น
GaussianNB(var_smoothing=1e-9).fit(X_train, y_train) เป็นจุดเริ่มได้ var_smoothing เติมความแปรปรวนเล็กน้อยเพื่อไม่ให้คำนวณมั่นใจเกินไปเมื่อคอลัมน์แทบไม่เปลี่ยน ค่า priors ใช้กำหนดสัดส่วนคลาสล่วงหน้าถ้ามีเหตุผล ส่วนงานข้อความใช้ make_pipeline(CountVectorizer(), MultinomialNB(alpha=1.0)) โดย alpha เป็นการเผื่อคำที่ยังไม่เคยพบ
ลองของใหม่และดูข้อผิดพลาด
predict ให้ชนิดที่คะแนนสูงสุด ส่วน predict_proba ให้คะแนนความน่าจะเป็น แต่ Naive Bayes อาจมั่นใจเกินจริงได้ ตรวจ confusion matrix และ precision/recall แยกแต่ละคลาส สำหรับข้อความให้ fit ตัว vectorizer เฉพาะชุดฝึก เพื่อไม่ให้คำศัพท์จากชุดทดสอบรั่วเข้ามา แล้วอ่านตัวอย่างที่จำแนกผิดเพื่อปรับการเตรียมข้อความ
ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ
priorsvar_smoothingsample_weightข้อมูลที่รับเข้ามา
รับ X เป็นค่าของหลักฐานแต่ละข้อและ y เป็นป้ายคลาส รูปแบบ X ขึ้นกับรุ่นย่อย เช่น GaussianNB รับตัวเลขต่อเนื่อง
GaussianNB: X = [ความยาวกลีบ, ความกว้างกลีบ] · y = ชนิดดอกไม้พารามิเตอร์ที่ใช้
- priors
- โอกาสเริ่มต้นของแต่ละคลาส ถ้าไม่ใส่จะเรียนรู้จากข้อมูล
- var_smoothing
- ค่าบวกเล็ก ๆ ที่ช่วยให้การคำนวณ variance ไม่เป็นศูนย์
- sample_weight
- น้ำหนักความสำคัญของแต่ละตัวอย่างระหว่าง fit
ผลลัพธ์ที่ได้
ได้คะแนน posterior probability ของทุกคลาสและป้ายคลาสที่มีคะแนนสูงสุด
predict → ชนิดดอกไม้ · งานข้อความให้เปลี่ยนเป็น MultinomialNBคำนวณทีละขั้น
- 01
นับ prior P(class) และเรียนรู้ distribution ของแต่ละ feature ภายในแต่ละคลาส
- 02
คำนวณ likelihood P(feature|class) ของหลักฐานทุกตัว โดยสมมติว่าแยกจากกันเมื่อรู้คลาส
- 03
รวมคะแนนตามกฎ Bayes แล้ว normalize เป็น probability ก่อนเลือกคลาสที่สูงที่สุด
ควรรู้อีกนิด — สมมติฐานอิสระมักไม่จริง ทำให้ probability มั่นใจเกิน แต่การจัดคลาสยังอาจทำงานได้ดี
04Make it yours
# ติดตั้ง: 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 แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที
Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง