ml/ library Learn by doing
UNSUPERVISED LEARNING · PYTHON / JAVASCRIPT

K-Means Clustering

หากลุ่มที่ซ่อนอยู่ในข้อมูล

LEARNING LEVEL1
พื้นฐานควรรู้มาก่อน · ระยะห่าง ค่าเฉลี่ย และ centroid
ลองใน Playground

01 Overall Concept

OVERALL CONCEPT

ไอเดียหลัก — K-Means ช่วยจัดของที่คล้ายกันให้อยู่กลุ่มเดียวกันโดยไม่ต้องมีคำตอบกำกับ เราบอกเพียงว่าต้องการกี่กลุ่ม แล้วโมเดลจะหาจุดศูนย์กลางและจัดสมาชิกให้ใกล้ศูนย์กลางของกลุ่มตัวเองมากที่สุด

ลองนึกภาพว่า — ลองเทลูกปัดหลายสีและหลายขนาดลงบนโต๊ะ แล้ววางถ้วย K ใบ ลูกปัดแต่ละเม็ดไปหาถ้วยที่ใกล้ที่สุด จากนั้นเราย้ายถ้วยไปกลางกองลูกปัด ทำซ้ำจนถ้วยและสมาชิกแทบไม่ขยับ

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

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

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

K-Means ต่างจากตัวอื่นหลายตัว เพราะเราไม่ได้มี “คำตอบถูก” ให้มันเรียนก่อน

สมมติเรามีลูกค้า 100,000 คน

เรารู้ข้อมูลว่าแต่ละคน

ซื้อกี่ครั้ง ใช้เงินเท่าไร เข้าร้านบ่อยแค่ไหน ชอบสินค้าแบบไหน

แต่เราไม่รู้ว่าควรแบ่งลูกค้าเป็นกลุ่มอะไร

เราบอก K-Means ว่า

“ช่วยแบ่งลูกค้าเป็น 4 กลุ่มให้หน่อย”

มันจะเริ่มจากสร้างจุดศูนย์กลาง 4 จุด

จากนั้นลูกค้าแต่ละคนจะถูกส่งไปอยู่กับจุดศูนย์กลางที่ใกล้ที่สุด

หลังจากนั้นจุดศูนย์กลางจะขยับไปตรงค่าเฉลี่ยของสมาชิกในกลุ่ม

แล้วจัดกลุ่มใหม่

ขยับอีก

จัดใหม่อีก

ทำซ้ำจนกลุ่มเริ่มนิ่ง

สุดท้ายเราอาจได้ว่า

Cluster 1 = ซื้อบ่อย ใช้เงินเยอะ Cluster 2 = ซื้อบ่อย แต่ยอดต่อครั้งต่ำ Cluster 3 = ซื้อไม่บ่อย แต่ยอดสูง Cluster 4 = ซื้อไม่บ่อยและยอดต่ำ

จากนั้นนักการตลาดถึงค่อยมาตั้งชื่อว่า

VIP Regular Big Spender Dormant

สิ่งสำคัญคือ K-Means ไม่รู้ความหมายของกลุ่ม

มันรู้แค่ว่า

“คนพวกนี้ดูคล้ายกัน”

มนุษย์ต้องเป็นคนตีความต่อ

ข้อจำกัดคือเราต้องบอกจำนวนกลุ่ม K ก่อน เช่น 3, 4 หรือ 5 และมันมักชอบกลุ่มที่มีรูปร่างค่อนข้างเป็นก้อนกลมๆ ถ้าข้อมูลมีรูปทรงประหลาดก็อาจแบ่งได้ไม่ดี

ภาพจำ: เอาคนทั้งหมดลงสนาม แล้วตั้งธง 4 ธง ทุกคนเดินไปหาธงที่ใกล้ที่สุด จากนั้นย้ายธงไปกลางกลุ่ม ทำซ้ำจนทุกอย่างลงตัว

03 How it works

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

  1. เริ่มจากลูกค้าที่เรายังไม่มีชื่อกลุ่มให้

    ให้ X เป็นตารางจำนวนครั้งซื้อและยอดใช้จ่ายในช่วงเวลาเดียวกัน หนึ่งคนต่อหนึ่งแถว เช่น [[2, 1000], [10, 9000], ...] ไม่ต้องมี y และอย่าใส่รหัสลูกค้าเป็น feature ตรวจค่าที่ขาดและจุดผิดปกติก่อน หากยอดใช้จ่ายต่างกันมาก อาจลองแปลง log1p แล้วค่อยปรับสเกล

  2. ตั้งสนามให้ทุกคอลัมน์มีเสียง

    ใช้ StandardScaler เพื่อให้หลักพันบาทไม่กลบจำนวนครั้งซื้อ เก็บ scaler ไว้ใช้กับลูกค้าใหม่ จากนั้นเลือก n_clusters=4 หมายถึงต้องการสี่กลุ่ม เริ่มด้วย KMeans(n_clusters=4, init='k-means++', n_init=10, random_state=42) โดย k-means++ ช่วยเลือกตำแหน่งตั้งต้นให้กระจายกัน

  3. ให้แต่ละคนเดินไปหาธงใกล้สุด

    ในแต่ละรอบ โมเดลคำนวณระยะจากลูกค้าทุกคนถึง centroid ทุกจุด แล้วให้ label ตามจุดที่ใกล้ที่สุด ระยะนี้มาจาก feature ที่ปรับสเกลแล้ว ไม่ใช่ความรู้สึกว่าเป็นลูกค้า VIP เมื่อแบ่งเสร็จจึงรู้ว่า centroid แต่ละจุดมีสมาชิกเป็นใครบ้าง

  4. ย้ายธงแล้วเริ่มรอบใหม่

    คำนวณค่าเฉลี่ยของสมาชิกแต่ละกลุ่มแล้วเลื่อน centroid ไปตรงนั้น ตัวอย่างบนพิกัดที่ปรับสเกลแล้ว ถ้าสมาชิกสองจุดคือ [0, 0] และ [2, 4] จุดกลางใหม่คือ [1, 2] จากนั้นจัดสมาชิกใหม่ ทำซ้ำจนเข้าเกณฑ์ tol หรือครบ max_iter ส่วน n_init=10 คือทดลองจุดเริ่มต้นสิบชุดและเลือกชุดที่ผลรวมระยะยกกำลังสองหรือ inertia ต่ำสุด

  5. รับผลแล้วแปลเป็นภาษาธุรกิจ

    เรียก labels = model.fit_predict(X_scaled) ได้หมายเลขกลุ่มต่อแถว และ cluster_centers_ ได้พิกัดศูนย์กลาง ใช้ scaler.inverse_transform ถ้าต้องการกลับเป็นหน่วยเดิม แล้วเทียบยอดเฉลี่ยและขนาดของแต่ละกลุ่มก่อนตั้งชื่อ VIP หรือ Regular หมายเลข 0–3 เป็นเพียงชื่อชั่วคราว ไม่ได้เรียงความสำคัญ และอาจสลับกันเมื่อฝึกใหม่

  6. ลอง K หลายค่าแล้วดูว่ากลุ่มใช้ได้ไหม

    ทดลอง K=2 ถึง 6 เปรียบเทียบ silhouette score ขนาดกลุ่ม ความเสถียรเมื่อเริ่มใหม่ และความหมายทางธุรกิจ Inertia ลดลงตาม K ที่เพิ่มจึงใช้เลือก K เพียงอย่างเดียวไม่ได้ ลูกค้าใหม่ต้องผ่าน scaler เดิมแล้วใช้ predict เพื่อเข้ากลุ่มเดิมโดยไม่ย้าย centroid ถ้าจะให้กลุ่มปรับตามพฤติกรรมใหม่ ต้องวางรอบฝึกใหม่และตรวจความหมายกลุ่มอีกครั้ง

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

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

DATA INX · features · no target yX = [จำนวนครั้งซื้อ, ยอดใช้จ่าย] · ไม่มี y
CALCULATEK-Means Clustering
n_clusters (K)max_itern_init
RESULTcluster labels + centersK=4 → label 0–3 และ centroid ทั้ง 4 จุด
เส้นทางของข้อมูล: จากค่าที่รับเข้า ผ่านการคำนวณด้วยพารามิเตอร์ ไปเป็นผลลัพธ์
INPUT

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

รับ X เป็นตารางตัวเลขเท่านั้น ไม่รับ y เพราะไม่มีคำตอบกำกับ หนึ่งแถวคือหนึ่งสิ่งที่ต้องการจัดกลุ่ม และควรปรับสเกลทุกคอลัมน์ให้ใกล้กัน

X = [จำนวนครั้งซื้อ, ยอดใช้จ่าย] · ไม่มี y
PARAMETERS

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

n_clusters (K)
จำนวนกลุ่มและจำนวน centroid ที่ต้องการ
max_iter
จำนวนรอบสูงสุดของการจับกลุ่มและย้ายศูนย์กลาง
n_init
จำนวนครั้งที่ลองจุดเริ่มต้นใหม่ แล้วเลือกผลที่ดีที่สุด
OUTPUT

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

ได้ cluster label ต่อหนึ่งแถว ตำแหน่ง centroids และ inertia ซึ่งเป็นผลรวมระยะกำลังสองภายในกลุ่ม

K=4 → label 0–3 และ centroid ทั้ง 4 จุด
CALCULATION

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

  1. 01

    วาง centroid K จุด แล้วคำนวณระยะจากข้อมูลทุกแถวไปยัง centroid ทุกจุด

  2. 02

    กำหนด label จาก centroid ที่ใกล้ที่สุด แล้วคำนวณค่าเฉลี่ยใหม่ของสมาชิกในแต่ละกลุ่ม

  3. 03

    ย้าย centroid ไปค่าเฉลี่ยและทำซ้ำจนตำแหน่งนิ่งหรือครบ max_iter จากนั้นเลือก run ที่ inertia ต่ำสุด

ควรรู้อีกนิด — K ต้องเลือกเอง และ Inertia มักลดลงเมื่อเพิ่ม K จึงไม่ควรใช้ตัวเลขนี้เลือก K เพียงอย่างเดียว เทคนิคนี้เหมาะกับกลุ่มค่อนข้างกลม ไวต่อ outlier และสเกลของข้อมูล ถ้าหน่วยต่างกันมาก ควรปรับสเกลก่อน

04 Make it yours

Python · scikit-learn
# ติดตั้ง: pip install numpy pandas scikit-learn matplotlibimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeans # ดาวน์โหลด sample.csv จาก Playground ไว้ข้างไฟล์นี้df = pd.read_csv("sample.csv")X = df[["x", "y"]]  # เปลี่ยนชื่อคอลัมน์เพื่อใช้ข้อมูลของคุณ model = KMeans(    n_clusters=3,  # จำนวนกลุ่ม: ลองเปลี่ยน 2–6    max_iter=20,    # จำนวนรอบสูงสุด    n_init=10,        # ลองจุดเริ่มต้นหลายชุด ลดโอกาสติดคำตอบที่ไม่ดี    random_state=42,  # ล็อก seed ให้รันซ้ำได้)labels = model.fit_predict(X)print("Inertia:", model.inertia_)plt.scatter(X.x, X.y, c=labels, cmap="viridis")plt.scatter(*model.cluster_centers_.T, marker="X", s=150)plt.show()

โค้ดอัปเดตตามพารามิเตอร์ใน Playground ด้านล่าง · เปลี่ยนไฟล์และคอลัมน์เพื่อใช้ข้อมูลของคุณ

05 Learn by playing

ลองเพิ่มหรือลด K แล้วสังเกตว่ากลุ่มและ Inertia เปลี่ยนอย่างไร

Sample dataset / Three groups● คำนวณใหม่เมื่อปรับค่า
จำนวนกลุ่มที่ต้องการแบ่ง (2–6)
จำนวนรอบสูงสุดในการขยับศูนย์กลาง
00252550507575100100Feature xFeature y
123

สี = กลุ่มที่โมเดลจัดให้ · + = ศูนย์กลาง

Inertia ↓47048
รอบที่คำนวณ6
จำนวนข้อมูล150

ข้อมูลสังเคราะห์ 150 จุด มี 2 features และ 3 กลุ่ม ใช้ seed 42 เพื่อให้ทดลองซ้ำได้ Playground ใช้ K-Means แบบเริ่มต้นชุดเดียว; Python ใช้ scikit-learn พร้อม n_init=10 จึงอาจได้ศูนย์กลางและ Inertia ต่างกัน ผลนี้ใช้เพื่อเรียนรู้ ไม่ใช่ benchmark บนข้อมูลจริง