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

Support Vector Machine

หาเส้นแบ่งที่มีพื้นที่ปลอดภัยกว้างที่สุด

LEARNING LEVEL3
ผสานหลายแนวคิดควรรู้มาก่อน · Logistic Regression, vector และระยะห่าง
ลองใน Playground

01Overall Concept

OVERALL CONCEPT

ไอเดียหลัก — Support Vector Machine หรือ SVM มองหาเส้นแบ่งที่เว้นทางว่างระหว่างสองกลุ่มให้กว้างที่สุด โมเดลสนใจจุดที่อยู่ใกล้เส้นแบ่งเป็นพิเศษ เพราะจุดเหล่านี้เป็นตัวกำหนดว่าเส้นควรวางตรงไหน

ลองนึกภาพว่า — ลองวางถนนคั่นระหว่างหมู่บ้านสีเขียวกับสีม่วง เราอยากให้ถนนกว้างและไม่ชนบ้าน บ้านที่อยู่ริมถนนที่สุดคือ support vectors ซึ่งคอยกำหนดแนวและความกว้างของถนน

ตัวอย่างการนำไปใช้ — แยกหมวดเอกสาร จำแนกภาพจาก feature จำนวนมาก หรือแก้โจทย์ที่มีข้อมูลไม่มหาศาลแต่ต้องการขอบเขตชัดเจน

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

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

SVM ไม่ได้คิดแค่ว่า

“ขอเส้นอะไรก็ได้ที่แบ่งสองกลุ่มออกจากกัน”

แต่มันถามว่า

“มีเส้นไหนที่แบ่งแล้วปลอดภัยที่สุด?”

สมมติมีคนใส่เสื้อแดงยืนทางซ้าย และเสื้อน้ำเงินอยู่ทางขวา

เราจะสร้างรั้วตรงกลาง

SVM ไม่สร้างรั้วชิดฝั่งแดงหรือชิดฝั่งน้ำเงิน แต่พยายามสร้างตรงจุดที่มี ช่องว่างจากสองฝ่ายมากที่สุด

ช่องว่างนี้เรียกว่า Margin

เหตุผลคือ ถ้าข้อมูลใหม่เข้ามาแล้วตำแหน่งคลาดเคลื่อนเล็กน้อย เรายังมีพื้นที่กันชนอยู่

สิ่งที่น่าสนใจมากของ SVM คือมันสามารถใช้สิ่งที่เรียกว่า Kernel เพื่อจัดการข้อมูลที่แบ่งด้วยเส้นตรงไม่ได้

ลองนึกภาพจุดสีแดงอยู่ตรงกลาง และสีน้ำเงินล้อมรอบเป็นวง

บนกระดาษ 2D เราลากเส้นตรงแบ่งไม่ได้

Kernel เหมือนยกข้อมูลจากกระดาษขึ้นมาเป็นภูเขาใน 3D แล้วจู่ๆ เราสามารถใช้แผ่นระนาบแบ่งได้

นี่คือเหตุผลที่ SVM เคยดังมากในงาน Machine Learning ก่อนยุค Deep Learning

ภาพจำ: สร้างรั้วที่มีพื้นที่กันชนกว้างที่สุด

03How it works

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

  1. เริ่มจากคนเสื้อสองสีในรูปตาราง

    ให้ X เป็น feature ตัวเลขของแต่ละตัวอย่าง และ y เป็นคลาส เช่นซื้อ/ไม่ซื้อ แบ่ง train/test และปรับสเกลด้วย StandardScaler ภายใน Pipeline ก่อน SVM ใช้ระยะและตำแหน่งของข้อมูล สเกลจึงมีผลกับรั้วที่มันจะสร้างโดยตรง

  2. หารั้วพร้อมพื้นที่กันชน

    สำหรับ kernel='linear' โมเดลหาน้ำหนักของเส้นแบ่งที่ทำให้ margin กว้าง พร้อมยอมให้บางจุดเข้ามาในพื้นที่กันชนหรืออยู่ผิดฝั่งเมื่อจำเป็น จุดฝึกที่มีอิทธิพลต่อคำตอบเรียกว่า support vectors จึงไม่ใช่เส้นที่แค่แบ่งข้อมูลฝึกถูกให้มากที่สุดอย่างเดียว

  3. เลือกว่าจะยอมผิดมากน้อยแค่ไหน

    ค่า C คุมราคาของการละเมิด margin เมื่อ C สูง โมเดลพยายามหลีกเลี่ยงการละเมิดมากขึ้น เมื่อ C ต่ำจะยอมประนีประนอมได้มาก เริ่ม make_pipeline(StandardScaler(), SVC(C=1.0, kernel='linear')) แล้ว fit(X_train, y_train) จากนั้นลอง C=0.1, 1, 10 บน validation

  4. ถ้ารั้วตรงยังแบ่งไม่ได้

    ลอง kernel='rbf' และ gamma='scale' โดย gamma คุมว่าจุดหนึ่งส่งผลในบริเวณกว้างแค่ไหน gamma สูงมักทำให้ขอบเขตละเอียดมากขึ้น ส่วน gamma ต่ำมักเรียบขึ้น ตัว kernel คำนวณความคล้ายเสมือนทำงานในพื้นที่ใหม่ โดยเราไม่จำเป็นต้องสร้างภูเขา 3 มิติขึ้นมาจริงๆ และ gamma ไม่มีผลกับ linear kernel

  5. อ่านคำตอบและเลือกความซับซ้อน

    predict ให้คลาส ส่วน decision_function ให้คะแนนฝั่งของรั้วซึ่งไม่ใช่ probability ถ้าต้องการ predict_proba ต้องตั้ง probability=True ก่อน fit และจะฝึกเพิ่มเพื่อประมาณความน่าจะเป็น ตรวจ precision/recall บน test และเลือก C กับ gamma จาก validation หากขอบเขตโค้งเล็กๆ ตามทุกจุดฝึกแต่ทดสอบแย่ ให้ลดความซับซ้อน

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

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

DATA INX · featuresy · targetX = feature ตัวเลขที่ปรับสเกล · y = ซื้อ / ไม่ซื้อ
CALCULATESupport Vector Machine
Ckernelgamma
RESULT0.800.150.05class / probabilitydecision_function → คะแนนฝั่งรั้ว · predict → คลาส
เส้นทางของข้อมูล: จากค่าที่รับเข้า ผ่านการคำนวณด้วยพารามิเตอร์ ไปเป็นผลลัพธ์
INPUT

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

รับ X เป็นตารางตัวเลขที่ควรปรับสเกล และ y เป็นป้ายคลาสหรือค่าต่อเนื่อง เหมาะกับ feature จำนวนมากและข้อมูลขนาดกลาง

X = feature ตัวเลขที่ปรับสเกล · y = ซื้อ / ไม่ซื้อ
PARAMETERS

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

C
ค่าปรับจุดผิดฝั่ง; สูงเน้นข้อมูลฝึก ต่ำเน้น margin
kernel
วิธีวัดความคล้าย เช่น linear, polynomial หรือ RBF
gamma
ระยะอิทธิพลของแต่ละจุดเมื่อใช้ RBF kernel
OUTPUT

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

ได้ป้ายคลาสและ decision score; probability มีได้เมื่อเปิด probability=True และคำนวณเพิ่ม

decision_function → คะแนนฝั่งรั้ว · predict → คลาส
CALCULATION

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

  1. 01

    คำนวณตำแหน่งของจุดใน feature space หรือ kernel space

  2. 02

    หา hyperplane ที่ทำให้ margin ถึงจุดใกล้ขอบกว้างที่สุด พร้อมค่าปรับจากจุดผิดฝั่ง

  3. 03

    เก็บ support vectors ที่กำหนดขอบเขต แล้วใช้ระยะมีเครื่องหมายจากขอบเขตเป็นคะแนนทำนาย

ควรรู้อีกนิด — ต้องปรับสเกล feature และ kernel SVM อาจช้ามากเมื่อจำนวนข้อมูลสูง

04Make it yours

Python · scikit-learn
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.svm import SVCfrom 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 = SVC(C=1.0, kernel="linear", probability=True, random_state=42)model.fit(X_train, y_train)pred = model.predict(X_test)print("Accuracy:", accuracy_score(y_test, pred))

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

05Learn by playing

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

Sample dataset / Three classes● คำนวณใหม่เมื่อปรับค่า
C ต่ำเน้น margin · C สูงเน้นจัดข้อมูลฝึกให้ถูก
พื้นที่สีคือคำทำนาย จุดคือคำตอบจริงFeature x → · Feature y ↑ · ขอบเข้ม = ชุดทดสอบ
Test accuracy93.3%
ชุดทดสอบ30 จุด
พารามิเตอร์ที่ลอง1.0

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