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

Multinomial Naive Bayes

นับคำแล้วดูว่าข้อความน่าจะอยู่หมวดไหน

LEARNING LEVEL2
ต่อยอดโดยตรงควรรู้มาก่อน · Gaussian Naive Bayes และข้อมูลแบบ count
ลองใน Playground

01Overall Concept

OVERALL CONCEPT

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

ลองนึกภาพว่า — เหมือนแยกข่าวจากร่องรอย ถ้าพบ goal และ team บ่อยก็เอนเอียงไปทางกีฬา ถ้าพบ chip และ code บ่อยก็เอนเอียงไปทางเทคโนโลยี

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

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

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

ลองทำตารางที่หนึ่งแถวคือหนึ่งข่าว และแต่ละคอลัมน์คือคำ เช่น goal กับ code ถ้าข่าวหนึ่งมี goal สามครั้งและ code หนึ่งครั้ง แถวนั้นจะเป็น [3,1]

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

ตอนอ่านข่าวใหม่ มันตรวจทุกคำแล้วรวมหลักฐาน คำที่เจอซ้ำจะมีผลซ้ำตามจำนวนครั้ง จึงต่างจาก Bernoulli NB ที่สนใจเพียงมีหรือไม่มีคำ

ถ้าคำหนึ่งไม่เคยปรากฏในหมวดใดเลย เราไม่อยากสรุปว่าหมวดนั้นเป็นไปไม่ได้ตลอดกาล alpha จึงเติมจำนวนสมมติเล็กน้อยให้ทุกคำ วิธีนี้เรียกว่า smoothing

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

ภาพจำ: นับร่องรอยจากคำแต่ละคำ แล้วรวมคะแนนว่าหมวดไหนมีหลักฐานมากที่สุด

03How it works

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

  1. เปลี่ยนเอกสารเป็นตาราง

    แบ่งข้อความและ label เป็น train/test ก่อน ใช้ CountVectorizer เรียนรู้ vocabulary เฉพาะชุดฝึก แล้วนับคำให้ได้ X ที่ทุกค่าไม่ติดลบ โค้ดสาธิตใช้ตาราง count สังเคราะห์โดยตรงเพื่อให้รันได้โดยไม่ดาวน์โหลดข้อมูล

  2. นับคำภายในคลาส

    ให้ N_cj เป็นจำนวนคำ j รวมในคลาส c และ V เป็นจำนวนคำใน vocabulary คำนวณ θ_cj=(N_cj+alpha)/(Σ_j N_cj+alpha×V) เช่นนับได้ [8,2] กับ alpha=1 จะได้ [9/12,3/12]

  3. รวมหลักฐานโดยไม่คูณตัวเลขเล็กซ้ำ

    ข่าว [2,0] ให้ score_c=log P(c)+2×log θ_c1 การใช้ log ป้องกันค่าความน่าจะเป็นที่คูณกันหลายครั้งเล็กจนคอมพิวเตอร์แทนไม่ได้ คลาสที่ score สูงสุดเป็นคำตอบ

  4. ฝึกและทำนาย

    ใช้ MultinomialNB(alpha=1.0).fit(X_train,y_train) แล้ว predict(X_test) ถ้ารับข้อความดิบควรวาง CountVectorizer กับโมเดลใน pipeline เดียวกัน ห้ามใช้ StandardScaler แบบลบค่าเฉลี่ยจน count ติดลบ

  5. วัดผลแยกตามหมวด

    ดู accuracy และ macro F1 รวมถึง confusion matrix ลอง alpha หลายค่าบน validation หากหมวดเล็กถูกกลบให้เทียบ Complement NB โค้ดและ Playground ใช้ 3 หมวดกับคำ 2 คำเพื่อเห็นขอบเขตง่าย จึงไม่ใช่ผลทดสอบเอกสารจริง

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

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

DATA INX · featuresy · targetคำรวมในคลาส [8,2] · alpha=1 · V=2
CALCULATEMultinomial Naive Bayes
alphafit_priorclass_prior
RESULT0.800.150.05class / probabilityสัดส่วนคำหลัง smoothing = [0.75,0.25]
เส้นทางของข้อมูล: จากค่าที่รับเข้า ผ่านการคำนวณด้วยพารามิเตอร์ ไปเป็นผลลัพธ์
INPUT

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

X เป็นจำนวนคำที่ไม่ติดลบ และ y เป็นหมวดเอกสาร

คำรวมในคลาส [8,2] · alpha=1 · V=2
PARAMETERS

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

alpha
จำนวนสมมติที่เติมต่อคำเพื่อ smoothing
fit_prior
เรียนรู้โอกาสคลาสจากความถี่ในชุดฝึกหรือไม่
class_prior
ระบุ prior เองหากมีเหตุผลรองรับ
OUTPUT

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

คลาสที่ได้คะแนนสูงที่สุด และ predict_proba ที่ควรตรวจ calibration ก่อนใช้เป็นความมั่นใจ

สัดส่วนคำหลัง smoothing = [0.75,0.25]
CALCULATION

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

  1. 01

    นับ N_cj ของแต่ละคำแยกคลาส

  2. 02

    คำนวณ θ_cj=(N_cj+alpha)/(ΣN_cj+alpha×V)

  3. 03

    เลือก argmax_c [log P(c)+Σx_j log θ_cj]

ควรรู้อีกนิด — CountVectorizer ต้อง fit จากข้อความฝึกเท่านั้น และถ้าใช้ภาษาไทยต้องเลือกวิธีตัดคำให้เหมาะกับงาน ตัวอย่างจำลองใช้ count โดยตรงจึงไม่ได้สาธิตการตัดคำไทย

04Make it yours

Python · scikit-learn
# ติดตั้ง: pip install numpy scikit-learn# ดาวน์โหลด sample.csv จากหน้านี้ แล้ววางไว้ข้างสคริปต์import numpy as np data = np.genfromtxt("multinomial-naive-bayes-sample.csv", delimiter=",", skip_header=1)X = data[:, :2] from sklearn.naive_bayes import MultinomialNBfrom sklearn.metrics import accuracy_score, classification_report y = data[:, 2].astype(int)# กันทุกแถวที่ 5 ไว้ทดสอบ ตามข้อมูลสาธิตใน Playground# งานจริงควรเลือก split ให้เหมาะกับเวลา/บุคคล/กลุ่มของข้อมูลis_test = np.arange(len(X)) % 5 == 0X_train, X_test = X[~is_test], X[is_test]y_train, y_test = y[~is_test], y[is_test]model = MultinomialNB(alpha=1)model.fit(X_train, y_train)pred = model.predict(X_test)print("Test accuracy:", accuracy_score(y_test, pred))print(classification_report(y_test, pred, labels=[0, 1, 2], zero_division=0)) 

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

05Learn by playing

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

Sample dataset / Word counts · Three classes● คำนวณใหม่เมื่อปรับค่า
เพิ่มจำนวนสมมติให้ทุกคำเพื่อไม่ให้คำที่ไม่เคยพบมีโอกาสเป็นศูนย์
พื้นที่สีคือคำทำนาย จุดคือคำตอบจริงword_1: 0–12 → · word_2: 0–12 ↑ · ขอบเข้ม = ชุดทดสอบ
Test accuracy93.3%
ชุดฝึกต่อคลาส72 / 36 / 12
พารามิเตอร์ที่ลอง1.0

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