DEV Community

Natnicha24
Natnicha24

Posted on

Artificial Intelligence (AI) K-Means Clustering

Clustering เป็นการจัดกลุ่มของปัญญาประดิษฐ์ โดยจะทำการนำข้อมูลที่มีความคล้ายกันจัดอยู่ในกลุ่มเดียวกัน การทำ Clustering เป็นการจัดกลุ่มแบบ "ไม่มีต้นแบบผลลัพธ์"

การทำ Clustering มีประโยชน์อย่างมาก เช่น การเก็บข้อมูลเพื่อทำ image processing , การค้นหาข้อมูลความรู้ในแหล่งข้อมูลจำนวนมาก การ Clustering จะทำให้ข้อมูลเป็นหมวดหมู่และเป็นระเบียบ

ในการทำ Clustering มี Algorithms ให้เลือกหลากหลายอย่าง เช่น K-Means Clustering , Density-Based Clustering , Mean-Shift Clustering , Hierarchical Clustering แต่ในบทความนี้เราจะมาดูตัวอย่างของ Algorithms ของ K-Means Clustering กัน

หลักการของการทำ K-Means Clustering นั้นคือการกำหนดจำนวนกลุ่มและหาจุด centroid ของแต่ละกลุ่มออกมา หลังจากนั้นเราจะเอาข้อมูลมาวางลงบนกราฟ หากข้อมูลใดใกล้กับจุด centroid ใด ก็จะถือว่าเป็นข้อมูลของกลุ่มนั้น แต่ยังไม่จบเพียงแค่นั้นหลังจากที่มีการจัดข้อมูลแล้ว ก็จะมีการย้ายจุด centroid และทำการจัดกลุ่มใหม่ การย้ายจุด centroid จะทำให้เกิดการย้ายกลุ่มของข้อมูล ซึ่งกระบวนการเหล่านี้จะเกิดซ้ำไปเรื่อยๆจนกว่าข้อมูลทั้งหมดนั้นจะไม่เกิดการย้ายกลุ่ม


หลังจากทำความเข้าใจในเรื่องของหลักการกันไปแล้วเราลองมาลงมือทำ K-Means Clustering กันดีกว่า

สำหรับข้อมูลที่จะนำมาใช้ในครั้งนี้ เป็นข้อมูลการคาดเดา final grade ของนักเรียนที่ศึกษาอยู่ในโรงเรียนมัธยมในประเทศโปรตุเกส ซึ่งเป็นข้อมูลที่มาจาก UCL Machine Learning Repository และทุกคนสามารถดาวน์โหลดข้อมูลนี้มาใช้ได้ทางลิงค์ที่แนบไว้ด้านล่าง

->DATASET LINK

โดยข้อมูลที่นำมาใช้งานจะประกอบไปด้วย
1.จำนวนแถว 396 แถว หมายถึง จำนวนนักเรียน 396 คน
2.จำนวนคอลัมน์ 33 คอลัมน์ โดยมีคำอธิบายแต่ละคอลัมน์ดังนี้

  • school - student's school (binary: 'GP' - Gabriel Pereira or 'MS' - Mousinho da Silveira)
  • sex - student's sex (binary: 'F' - female or 'M' - male)
  • age - student's age (numeric: from 15 to 22)
  • address - student's home address type (binary: 'U' - urban or 'R' - rural)
  • famsize - family size (binary: 'LE3' - less or equal to 3 or 'GT3' - greater than 3)
  • Pstatus - parent's cohabitation status (binary: 'T' - living together or 'A' - apart)
  • Medu - mother's education (numeric: 0 - none, 1 - primary education (4th grade), 2 – 5th to 9th grade, 3 – secondary education or 4 – higher education)
  • Fedu - father's education (numeric: 0 - none, 1 - primary education (4th grade), 2 – 5th to 9th grade, 3 – secondary education or 4 – higher education)
  • Mjob - mother's job (nominal: 'teacher', 'health' care related, civil 'services' (e.g. administrative or police), 'at_home' or 'other')
  • Fjob - father's job (nominal: 'teacher', 'health' care related, civil 'services' (e.g. administrative or police), 'at_home' or 'other')
  • reason - reason to choose this school (nominal: close to 'home', school 'reputation', 'course' preference or 'other')
  • guardian - student's guardian (nominal: 'mother', 'father' or 'other')
  • traveltime - home to school travel time (numeric: 1 - <15 min., 2 - 15 to 30 min., 3 - 30 min. to 1 hour, or 4 - >1 hour)
  • studytime - weekly study time (numeric: 1 - <2 hours, 2 - 2 to 5 hours, 3 - 5 to 10 hours, or 4 - >10 hours)
  • failures - number of past class failures (numeric: n if 1<=n<3, else 4)
  • schoolsup - extra educational support (binary: yes or no)
  • famsup - family educational support (binary: yes or no)
  • paid - extra paid classes within the course subject (Math or Portuguese) (binary: yes or no)
  • activities - extra-curricular activities (binary: yes or no)
  • nursery - attended nursery school (binary: yes or no)
  • higher - wants to take higher education (binary: yes or no)
  • internet - Internet access at home (binary: yes or no)
  • romantic - with a romantic relationship (binary: yes or no)
  • famrel - quality of family relationships (numeric: from 1 - very bad to 5 - excellent)
  • freetime - free time after school (numeric: from 1 - very low to 5 - very high)
  • goout - going out with friends (numeric: from 1 - very low to 5 - very high)
  • Dalc - workday alcohol consumption (numeric: from 1 - very low to 5 - very high)
  • Walc - weekend alcohol consumption (numeric: from 1 - very low to 5 - very high)
  • health - current health status (numeric: from 1 - very bad to 5 - very good)
  • absences - number of school absences (numeric: from 0 to 93)

  • G1 - first period grade (numeric: from 0 to 20)

  • G2 - second period grade (numeric: from 0 to 20)

  • G3 - final grade (numeric: from 0 to 20, output target)

ถ้าทุกคนเข้าใจในข้อมูลแล้วเราจะเริ่มการทำ Clustering ให้ข้อมูลนี้กัน :)


ขั้นที่1 : ดาวน์โหลดข้อมูล
-ก่อนที่ทุกคนจะเริ่มทำการ Clustering ได้จะต้องโหลดข้อมูลมาก่อน ซึ่งสามารถเขียนโค้ดได้ตามนี้เลย หรือทุกคนจะเปลี่ยน url เป็นลิงค์ที่อยู่ข้อมูลใน github ของทุกคนเองก็ได้

import pandas as pd
url = 'https://raw.githubusercontent.com/Natnicha24/grade-ai/master/student-mat.csv'
studentData = pd.read_csv(url, sep = ',')
studentData.head()
Enter fullscreen mode Exit fullscreen mode

-ซึ่งเมื่อทุกคนกดรันแล้วจะได้ผลเหมือนตัวอย่างดังนี้

Image description


ขั้นที่2 : การจัดการข้อมูล
-เนื่องจากที่อธิบายไปข้างต้นว่าข้อมูลที่เรานำมาใช้กันในครั้งนี้มีจำนวนคอลัมน์ค่อนข้างมาก เราสามารถเลือกเฉพาะข้อมูลที่เกี่ยวข้องเพื่อให้ดูข้อมูลได้ง่ายขึ้น
-ตามตัวอย่างโค้ดด้านล่างคือการเลือกคอลัมน์ทั้งหมด 8 คอลัมน์ ได้แก่ school,sex,age,failures,absences,G1,G2,G3

studentData =studentData[['school' , 'sex' , 'age' , 'failures' , 'absences' , 'G1' , 'G2' , 'G3',
      ]]

studentData.head()
Enter fullscreen mode Exit fullscreen mode

-เมื่อรันแล้วจะได้ตัวอย่างดังภาพ

Image description


ขั้นที่3 : หาค่า k
-ขั้นตอนนี้ถือว่าเราจะเริ่มการทำ k-means clustering กันแล้ว ซึ่งการทำ k-means clustering นั้นจำเป็นจะต้องรู้จำนวนของกลุ่ม(k) โดยเราสามารถกำหนดจำนวนกลุ่มด้วยตัวเองแบบสุ่มก็ได้หรือจะทำการหาจำนวนกลุ่มที่สมควรจะแบ่งโดยเขียนตามโค้ดได้ ดังต่อไปนี้

  • เลือกข้อมูลทั้งหมด2ตัวเป็นข้อมูลที่เราจะใช้เป็น แกน x และ y ในที่นี้เราจะลองเลือกเป็นคอลัมน์ absences(การขาดเรียน) และ G3(คะแนนเกรดปลายภาค)
studentData.columns
data = studentData[['absences','G3']]
Enter fullscreen mode Exit fullscreen mode
  • ต่อมาเรายังคงอยู่ในขั้นตอนของการหาจำนวนกลุ่ม(k) โดยต่อไปเราจะทำการกำหนด range ของข้อมูลที่เราต้องการทำ k-means clustering โดยในบทความนี้เราจะลองกำหนด range เป็น 1-20 และนำไปหาค่า sum of square distances ซึ่งสามารถเขียนได้ตามโค้ดด้านล่าง
from sklearn.cluster import KMeans
w = []
K = range(1,20)

for k in K: #range(1,20):
    cls = KMeans(n_clusters=k,n_init='auto')
    cls.fit(data)
    w.append(cls.inertia_)
Enter fullscreen mode Exit fullscreen mode
  • ซึ่งเราสามารถดูค่า sum of square distances โดยเขียนโค้ดตามด้านล่างนี้
cls.inertia_
Enter fullscreen mode Exit fullscreen mode
  • เมื่อรันแล้วจะได้ค่า sum of square distances ออกมาดังภาพ

Image description

  • ต่อมา เรามาถึงขั้นตอนสุดท้ายในการหาจำนวนกลุ่ม(k)กันแล้ว นั่นคือการนำค่าที่เราได้นั้นมาพล๊อตเป็นกราฟ ทุกคนอาจจะเกิดคำถามว่าค่า k จะอยู่ส่วนไหนของกราฟกันล่ะ?? คำตอบก็คือ จุดที่มีการหักของกราฟซึ่งแสดงให้เห็นถึงการลดลงของข้อมูลอย่างรวดเร็วนั่นเอง

  • โดยทุกคนสามารถพล๊อตกราฟโดยเขียนโค้ดดังนี้

import matplotlib.pyplot as plt
plt.plot(K,w)
plt.ylabel('inertia')
plt.xlabel('number of cluster')
Enter fullscreen mode Exit fullscreen mode
  • จะได้กราฟดังนี้

Image description

  • ตามรูปเราสามารถประมาณค่าได้ว่าจุดที่แกน x เท่ากับ 4 เป็นจุดที่แสดงถึงการลดลงของข้อมูลอย่างรวดเร็ว

ขั้นที่4 : ทำการ Clustering
-เรามาถึงขั้นตอนของการทำ Clustering กันแล้วโดยในขั้นตอนนี้ผลสุดท้ายเราจะได้กราฟที่จัดกลุ่มข้อมูลของเราให้เรียบร้อย

  • อย่างแรกที่เราต้องทำคือการนำค่า k หรือจำนวนกลุ่มที่เราได้ในขั้นตอนที่ผ่านมา มาใช้งาน โดยการเขียนโค้ดดังนี้
cls = KMeans(n_clusters=4,n_init='auto')
cls.fit(data)
Enter fullscreen mode Exit fullscreen mode
  • เมื่อรันจะได้ดังนี้

Image description

  • ต่อมาเป็นอีกหนึ่งขั้นตอนสำคัญคือการหาจุด centroid หรือจุดที่เป็นค่าเฉลี่ยของแต่ละกลุ่ม ซึ่งทุกคนอาจจะพอเข้าใจแล้วว่าทำไมสิ่งที่เรากำลังทำอยู่นี้ถึงเรียกว่า K-means clustering นั่นเพราะเรามีการนำค่าเฉลี่ยมาใช้นั่นเอง โดยทุกคนสามารถหาจุด centroid ได้ตามโค้ดด้านล่างนี้เลย
centroid = pd.DataFrame(cls.cluster_centers_,
                        columns=data.columns)
centroid
Enter fullscreen mode Exit fullscreen mode
  • โดยจะได้ค่าดังนี้เมื่อรันออกมา

Image description

  • ขั้นตอนถัดไปเป็นขั้นตอนที่สามารถอธิบายวิธีการทำงานของการจัดกลุ่มโดย k-means clustering ได้ดีมาก ในขั้นตอนนี้ที่เราเขียนโค้ดขึ้นมา จะเป็นการนำข้อมูลมาวางแล้วหาว่าใกล้กับจุด centroid ใดมากที่สุด หากใกล้จุด centroid ใดมากที่สุดก็จะเป็นข้อมูลของกลุ่มนั้นนั่นเอง

  • โดยเขียนโค้ดดังนี้

import numpy as np
x = data
k = [data,centroid]
x = pd.concat(k)
x['cluster'] = np.concatenate((cls.predict(data),[20,20,20,20]))
x.head()
Enter fullscreen mode Exit fullscreen mode
  • จะได้ผลดังนี้

Image description

  • ขั้นตอนสุดท้าย เราจะมาพล๊อตกราฟเพื่อดูการจัดกลุ่มข้อมูลกัน โดยเขียนโค้ดตามนี้
import seaborn as sns

s = sns.pairplot(x_vars='absences',y_vars='G3',hue='cluster',plot_kws={"s": 80},
                 data=x,palette='deep' )
new_labels = ['0','1','2','3','centroid']
for t, l in zip(s._legend.texts, new_labels): t.set_text(l)
s._legend.set_bbox_to_anchor((1.2, 0.5))
Enter fullscreen mode Exit fullscreen mode
  • และจะได้ผลตามนี้

Image description

และภาพนี้ก็เป็นผลสรุปของการทำ K-Means Clustering ที่พวกเราทดลองทำกัน โดยแบ่งข้อมูลเป็น 4 กลุ่มด้วยกัน โดยจุดสีม่วงจะเป็นจุด centroid แล้วข้อมูลจะถูกแบ่งเป็นสีต่างๆ
หากทุกคนอยากเห็นการแบ่งกลุ่มที่มากกว่า4กลุ่มก็สามารถเปลี่ยนจำนวนของกลุ่มได้ก่อนการทำ clustering ทุกคนก็จะเห็นการแบ่งกลุ่มแบบใหม่ที่เกิดขึ้นกับข้อมูล

ขอบคุณทุกคนที่อ่านบทความนี้จนจบนะคะ หวังว่าจะสามารถเป็นประโยชน์ต่อใครได้บ้าง :)
หากผิดพลาดประการใดขออภัยมา ณ ที่นี้ด้วยค่ะ


References
ขอบคุณ DATASET จาก:
https://www.kaggle.com/datasets/dipam7/student-grade-prediction?resource=download
โค้ดตัวอย่างก่อนนำมาดัดแปลง :
https://colab.research.google.com/drive/12MEZXoT5nJrEjew3t6ULcdHGgz0fn_lb

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more