01Overall Concept
ไอเดียหลัก — k-Nearest Neighbors หรือ kNN ตัดสินข้อมูลใหม่ด้วยการถามตัวอย่างที่อยู่ใกล้ที่สุด ถ้าเพื่อนบ้านส่วนใหญ่เป็นกลุ่มใด ก็ทำนายเป็นกลุ่มนั้น หรือถ้าเป็นตัวเลขก็ใช้ค่าเฉลี่ยของเพื่อนบ้าน
ลองนึกภาพว่า — ถ้าเจอผลไม้ที่ไม่รู้จัก เราอาจนำไปวางใกล้ผลไม้ตัวอย่างแล้วดูว่าเพื่อนบ้านมีสี ขนาด และรูปทรงคล้ายชนิดใด วิธีนี้ไม่ต้องสร้างกฎยาว ๆ ล่วงหน้า
ตัวอย่างการนำไปใช้ — จำแนกลายมือ แนะนำสิ่งของจากคนที่มีพฤติกรรมคล้ายกัน หรือใช้เป็นโมเดลเบื้องต้นกับข้อมูลขนาดไม่ใหญ่มาก
02อธิบายภาษาคนเข้าใจง่ายๆ
kNN เป็นหนึ่งในอัลกอริทึมที่เข้าใจง่ายที่สุด
สมมติเรามีนักเรียนใหม่เข้ามาหนึ่งคน และอยากเดาว่าเขาน่าจะชอบวิชาวิทยาศาสตร์หรือศิลปะ
แทนที่จะสร้างสมการ เราไปดูนักเรียนที่มีบุคลิกคล้ายเขาที่สุด 5 คน
ถ้าใน 5 คนนี้
4 คนชอบวิทยาศาสตร์ 1 คนชอบศิลปะ
เราก็ทายว่านักเรียนใหม่มีแนวโน้มชอบวิทยาศาสตร์
ตัว k ก็คือจำนวนเพื่อนบ้านที่เราจะถาม
k = 1 → ดูคนที่ใกล้ที่สุดคนเดียว k = 5 → ดู 5 คน k = 20 → ดู 20 คน
ถ้า k เล็กเกินไป โมเดลอาจไวต่อ Noise มาก เช่นเจอเพื่อนบ้านแปลกๆ คนเดียวก็ตัดสินผิด
ถ้า k ใหญ่เกินไป ก็อาจกลืนความแตกต่างของกลุ่มเล็กๆ ไป
อีกเรื่องสำคัญคือคำว่า “ใกล้” ต้องนิยามผ่านระยะทางของข้อมูล ดังนั้นการจัด Scale ของข้อมูลสำคัญมาก
เช่น อายุ 30 กับ 35 ต่างกัน 5 แต่รายได้ 30,000 กับ 100,000 ต่างกัน 70,000 ถ้าไม่จัด Scale ตัวรายได้อาจครองทุกอย่าง
ภาพจำ: อยากรู้ว่าคนนี้เป็นพวกไหน ก็หันไปถามคนที่ยืนรอบตัวเขา
03How it works
ค่อยๆ ทำไปด้วยกัน ตั้งแต่ข้อมูลแถวแรกจนถึงการตรวจคำตอบ
เตรียมข้อมูลเพื่อนบ้านให้เทียบกันได้
สมมติ X เป็นคะแนนกิจกรรมวิทยาศาสตร์และศิลปะของนักเรียน ส่วน y คือวิชาที่ชอบ แบ่งชุดฝึกและทดสอบก่อน ถ้าต้องเพิ่มอายุหรือรายได้ ต้องปรับสเกลด้วย StandardScaler ที่เรียนจาก train เท่านั้น ไม่เช่นนั้นคอลัมน์ที่มีตัวเลขใหญ่จะครองระยะทางทั้งหมด
ตอนฝึกยังไม่สร้างสูตรซับซ้อน
KNeighborsClassifier เก็บข้อมูลฝึกไว้เพื่อใช้ค้นหาเพื่อนบ้าน เมื่อมีนักเรียนใหม่จึงค่อยคำนวณระยะจาก feature ของเขาไปยังคนในชุดฝึก แล้วเรียงจากใกล้ไปไกล ดังนั้น fit มักเบา แต่การ predict อาจช้าลงเมื่อข้อมูลสะสมมาก
ให้เพื่อนบ้านช่วยตอบ
ถ้า n_neighbors=5 จะใช้ห้าคนใกล้ที่สุด ถ้าสี่คนชอบวิทยาศาสตร์และหนึ่งคนชอบศิลปะ เมื่อ weights='uniform' จะตอบวิทยาศาสตร์และให้สัดส่วน 4/5 สำหรับคลาสนั้น หาก weights='distance' คนที่ใกล้กว่าจะมีน้ำหนักมากกว่า ตัวเลขสัดส่วนนี้ยังไม่ใช่การรับรองความน่าจะเป็นในโลกจริง
เริ่มลงมือและหมุนสามปุ่ม
ใช้ make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=5, weights='uniform', p=2)) แล้ว fit(X_train, y_train) n_neighbors คือ k, weights คือวิธีรวมเสียง และ p=2 ใช้ระยะ Euclidean ส่วน p=1 ใช้ผลรวมระยะห่างแต่ละแกน อย่าเลือก k มากกว่าจำนวนแถวฝึกในแต่ละ fold
เลือกเพื่อนบ้านจากผลทดสอบ
ลอง k เช่น 3, 5, 11, 21 ผ่าน cross-validation ภายใน train แล้วตรวจ accuracy และ confusion matrix บน test k เล็กมักไวต่อจุดผิดปกติ ส่วน k ใหญ่เกินไปอาจกลืนกลุ่มเล็ก หากหลาย feature ไม่เกี่ยวกับคำตอบ ลองคัดออก เพราะคำว่าใกล้จะเสียความหมายเมื่อเทียบข้อมูลที่ไม่ช่วยบอกความคล้ายจริง
ข้อมูล พารามิเตอร์ และภาพรวมการคำนวณ
n_neighbors (k)metricweightsข้อมูลที่รับเข้ามา
รับ X เป็นตารางตัวเลขที่ปรับสเกลแล้วและ y เป็นคลาสหรือค่าต่อเนื่อง โมเดลเก็บทุกแถวไว้เพื่อใช้ตอนทำนาย
X = [คะแนนกิจกรรมวิทยาศาสตร์, คะแนนศิลปะ] · y = วิชาที่ชอบพารามิเตอร์ที่ใช้
- n_neighbors (k)
- จำนวนเพื่อนบ้านที่นำมาตัดสิน
- metric
- สูตรระยะห่าง เช่น Euclidean หรือ Manhattan
- weights
- ให้ทุกเพื่อนเสียงเท่ากันหรือให้จุดใกล้มีน้ำหนักมากกว่า
ผลลัพธ์ที่ได้
ได้ป้ายคลาสหรือค่าตัวเลขหนึ่งค่าต่อแถว และสามารถดูระยะกับดัชนีของเพื่อนบ้านได้
k=5, uniform: วิทยาศาสตร์ 4 คน / ศิลปะ 1 คน → วิทยาศาสตร์คำนวณทีละขั้น
- 01
คำนวณระยะจากข้อมูลใหม่ไปยังข้อมูลฝึกทุกแถวด้วย metric ที่เลือก
- 02
เรียงระยะจากน้อยไปมากและหยิบเฉพาะ k แถวแรก
- 03
classification ใช้การโหวต ส่วน regression ใช้ค่าเฉลี่ย โดยอาจถ่วงน้ำหนักตามระยะ
ควรรู้อีกนิด — ทำนายช้าเมื่อข้อมูลใหญ่ ไวต่อสเกล feature และมิติสูงทำให้ระยะทางมีความหมายน้อยลง
04Make it yours
# ติดตั้ง: pip install numpy scikit-learn matplotlibfrom sklearn.neighbors import KNeighborsClassifierfrom 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 = KNeighborsClassifier(n_neighbors=7)model.fit(X_train, y_train)pred = model.predict(X_test)print("Accuracy:", accuracy_score(y_test, pred))โค้ดเปลี่ยนตามค่าที่เลือกใน Playground · แต่ละภาษาใช้ข้อมูลตัวอย่างตามที่ระบุในโค้ด
05Learn by playing
ปรับ จำนวนเพื่อนบ้าน (k) แล้วสังเกตรูปแบบคำทำนายและตัวชี้วัดที่คำนวณใหม่ทันที
Playground เป็น implementation เพื่อการเรียนรู้ที่คำนวณในเบราว์เซอร์ ส่วนโค้ด Python ใช้ scikit-learn จึงอาจให้ค่าต่างกันเล็กน้อยจากรายละเอียดการ optimize และค่าเริ่มต้นของไลบรารี ผลนี้ไม่ใช่ benchmark บนข้อมูลจริง