Professional Documents
Culture Documents
Chủ Đề
Mục lục
1 Lý thuyết 2
1 Lý thuyết
K-mean clustering là một phương pháp để tìm các cụm và hạt nhân - trung tâm của cụm
trong một tập hợp dữ liệu không được gắn nhãn. Người ta chọn số lượng hạt nhân cụm mong
muốn phân chẳng hạn như k cụm. Thuật toán K-mean di chuyển lặp đi lặp lại các hạt nhân để
giảm thiểu tổng số trong phương sai cụm. Với một tập hợp các hạt nhân ban đầu, thuật toán
Kmeans lặp lại hai bước:
• Đối với mỗi hạt nhân, tính toán khoảng cách giữa các training ponit với nó và nếu gần nó
hơn -> sẽ gán là cụm của hạt nhân đấy.
• Sau khi phân được cụm như ở bước trên, thì tiếp theo các training point của các cụm tính
toán vector trung bình để được vị trí của hạt nhân mới và lặp lại bước trên đến khi không thể
thay đổi được vị trí hạt nhân nữa.
Phân cụm có nhiều hữu ích đặc biệt và cực kỳ phổ biến trong ngành khoa học dữ liệu. Trong
đó như :
Phân tích cụm được sử dụng rộng rãi trong nghiên cứu thị trường, nhận dạng mẫu, phân
tích dữ liệu và xử lý ảnh. Phân tích cụm cũng có thể giúp các nhà khoa học dữ liệu khám phá
ra các nhóm khác hàng của họ. Và họ có thể mô tả đặc điểm nhóm khách hàng của mình dựa
trên lịch sử mua hàng.
Trong lĩnh vực sinh học, nó có thể được sử dụng để xác định phân loại thực vật và động vật,
phân loại các gen có chức năng tương tự và hiểu sâu hơn về các cấu trúc vốn có của quần thể.
Vậy để giải các bài toán về phân cụm cần có công cụ/phương pháp, K-means là một trong
những thuật toán được sử dụng phổ biến nhất. Trong hướng dẫn này mình sẽ bắt đầu với cơ sở
lý thuyết của thuật toán K-means, sau đó sẽ ứng dụng vào 1 ví dụ đơn giản với Python và thư
viện Sklearn.
Ví dụ: Một công ty muốn tạo ra những chính sách ưu đãi cho những nhóm khách hàng khác
nhau dựa trên sự tương tác giữa mỗi khách hàng với công ty đó (số năm là khách hàng; số tiền
khách hàng đã chi trả cho công ty; độ tuổi; giới tính; thành phố; nghề nghiệp; . . . ). Giả sử công
ty đó có rất nhiều dữ liệu của rất nhiều khách hàng nhưng chưa có cách nào chia toàn bộ khách
hàng đó thành một số nhóm/cụm khác nhau. Nếu một người biết Machine Learning được đặt
câu hỏi này, phương pháp đầu tiên anh (chị) ta nghĩ đến sẽ là K-means Clustering. Vì nó là một
trong những thuật toán đầu tiên mà anh ấy tìm được trong các cuốn sách, khóa học về Machine
Learning. Và tôi cũng chắc rằng anh ấy đã đọc blog Machine Learning cơ bản. Sau khi đã phân
ra được từng nhóm, nhân viên công ty đó có thể lựa chọn ra một vài khách hàng trong mỗi nhóm
để quyết định xem mỗi nhóm tương ứng với nhóm khách hàng nào. Phần việc cuối cùng này cần
sự can thiệp của con người, nhưng lượng công việc đã được rút gọn đi rất nhiều.
Ý tưởng đơn giản nhất về cluster (cụm) là tập hợp các điểm ở gần nhau trong một không
gian nào đó (không gian này có thể có rất nhiều chiều trong trường hợp thông tin về một điểm
dữ liệu là rất lớn). Hình bên dưới là một ví dụ về 3 cụm dữ liệu (từ giờ tôi sẽ viết gọn là cluster).
Giả sử mỗi cluster có một điểm đại diện (center) màu vàng. Và những điểm xung quanh mỗi
center thuộc vào cùng nhóm với center đó. Một cách đơn giản nhất, xét một điểm bất kỳ, ta xét
xem điểm đó gần với center nào nhất thì nó thuộc về cùng nhóm với center đó. Tới đây, chúng
ta có một bài toán thú vị: Trên một vùng biển hình vuông lớn có ba đảo hình vuông, tam giác,
và tròn màu vàng như hình trên. Một điểm trên biển được gọi là thuộc lãnh hải của một đảo
nếu nó nằm gần đảo này hơn so với hai đảo kia . Hãy xác định ranh giới lãnh hải của các đảo.
Hình dưới đây là một hình minh họa cho việc phân chia lãnh hải nếu có 5 đảo khác nhau
được biểu diễn bằng các hình tròn màu đen:
Chúng ta thấy rằng đường phân định giữa các lãnh hải là các đường thẳng (chính xác hơn
thì chúng là các đường trung trực của các cặp điểm gần nhau). Vì vậy, lãnh hải của một đảo sẽ
là một hình đa giác.
Cách phân chia này trong toán học được gọi là Voronoi Diagram.
Trong không gian ba chiều, lấy ví dụ là các hành tinh, thì (tạm gọi là) lãnh không của mỗi
hành tinh sẽ là một đa diện. Trong không gian nhiều chiều hơn, chúng ta sẽ có những thứ (mà
tôi gọi là) siêu đa diện (hyperpolygon).
Với
||xi − mk ||2 2
tổng bình phương của mỗi giá trị
(xi − mk )
Thêm vào đó, vì xi được phân vào cụm k nên yik = 1, yij = 0, jk. Khi đó, biểu thức trên được
viết lại là:
K
X
yik ||xi + mk ||2 2 = yij ||xi − mj ||
j=1
Trong đó, Y = [[y1 , y2 , . . . , yN ], M = [m1 , m2 , . . . , mK ] lần lượt là các ma trận được tạo bởi
label vector của mỗi điểm dữ liệu và tâm của mỗi cụm. L(Y, M) là hàm mất mát của bài toán
phân cụm K – means với ràng buộc như ở phương trình (1). Tóm lại ta cần tối ưu bài toán sau:
N X
X K
Y, M = argminY,M yij ||xi − mj ||
i=1 j=1
K
X
Thỏa điều kiện: yij ∈(0, 1) mọi ij yik = 1 với mọi i
k=1
K
X
Thỏa điều kiện: yij ∈(0, 1) mọi ij yik = 1 với mọi i
k=1
Vì chỉ có một phần tử của label vector yi = 1 nên bài toán có thể được viết dạng dưới dạng
đơn giản hơn:
j = argmin||xi − mj ||2 2
Vì ||xi − mj ||2 2 chính là bình phương khoảng cách từ điểm xi đến tâm mj , ta có thể kết luận
rằng mỗi điểm xi thuộc vào cụm có tâm gần nó nhất. Từ đó ta có thể dễ dàng suy ra label vector
của từng điểm dữ liệu.
Bài toán 2: Cố định Y, tìm M Giả sử đã tìm được cụ cho từng điểm, tìm tâm mới cho mỗi
cụm để hàm mất mát đạt giá trị nhỏ nhất. Nếu chúng ta đã xác định được label vector cho từng
điểm dữ liệu, bài toán tìm center cho mỗi cụm được rút gọn thành:
Để ý rằng hàm mục tiêu là một hàm liên tục và có đạo hàm xác định tại mọi điểm mj . Vì
vậy, ta có thể tìm nghiệm bằng phương pháp giải phương trình đạo hàm bằng không. Đặt l(mj
) là hàm mục tiêu bên trong dấu argmin của (10.7), ta cần giải phương trình sau đây:
Để ý rằng mẫu số chính là tổng số điểm dữ liệu trong cụm j, tử số là tổng các điểm dữ liệu
trong cụm j. Nói cách khác, mj là trung bình cộng (mean) của các điểm trong cụm j
Nói cách khác, WSS là tổng bình phương của khoảng cách giữa mỗi đối tượng dữ liệu và tâm
gần nhất. q(i) là giá trị đặc trưng của trọng tâm liên quan đến đối tượng thứ i. Nếu đối tượng
tương đối gần với trọng tâm tương ứng của chúng, WSS tương đối nhỏ. Thuật toán Elbow chỉ
ra số cụm k sao cho WSSk và WSSk+1 sai kém không đáng kể
Để xác định số lượng cụm tối ưu ở hình trên, chúng ta phải chọn giá trị của k tại “khuỷu
tay” tức là điểm mà sau đó biến dạng / quán tính bắt đầu giảm theo kiểu tuyến tính.Quan sát
thấy số cụm tối ưu cho dữ liệu là 3.
import cv2
from sklearn.cluster import KMeans
import os
import numpy as np
import pickle
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
c_data_path = "data/cars"
Tạo một hàm getfeature để trích xuất một đặc điểm (cường độ) từ một hình ảnh. Nó thể
hiện độ sáng hoặc cường độ tổng thể của hình ảnh bằng cách tổng hợp các giá trị pixel và chuẩn
hóa kết quả. Loại tính năng này có thể được sử dụng trong các nhiệm vụ phân tích hình ảnh
hoặc học máy khác nhau, trong đó cần có sự thể hiện nhỏ gọn nội dung hình ảnh.
def get_feature(img):
intensity = img.sum(axis=1)
intensity = intensity.sum(axis=0) / (255 * img.shape[0] * img.shape[1])
return intensity
return
Hàm loaddata để load tất cả các ảnh vào biến X và tất cả nhãn tên file vào biến L
def load_data(data_path=c_data_path):
try:
with open('data.pickle', 'rb') as handle:
X = pickle.load(handle)
with open('label.pickle', 'rb') as handle:
L = pickle.load(handle)
return X,L
except:
X = []
L = []
for file in os.listdir(data_path):
print(file)
c_x = get_feature(cv2.imread(os.path.join(data_path, file)))
X.append(c_x)
L.append(file)
X = np.array(X)
L = np.array(L)
with open('data.pickle', 'wb') as handle:
pickle.dump(X, handle, protocol=pickle.HIGHEST_PROTOCOL)
with open('label.pickle', 'wb') as handle:
pickle.dump(L, handle, protocol=pickle.HIGHEST_PROTOCOL)
return X,L
Mảng distortions dùng để tính các giá trị distorsion tương ứng với k từ 1 đến 10 sau đố vẽ
đồ thị elbow
distortions = []
K = range(1,10)
for k in K:
kmeanModel = KMeans(n_clusters=k)
kmeanModel.fit(X)
distortions.append(kmeanModel.inertia_)
plt.figure(figsize=(16,8))
plt.plot(K, distortions, 'bx-')
plt.xlabel('k')
plt.ylabel('Distortion')
plt.title('The Elbow Method showing the optimal k')
plt.show()
Phân cụm với k=4(chọn trong đồ thị elbow trên) và fit vào X
kmeans = KMeans(n_clusters=4).fit(X)
for i in range(len(kmeans.labels_)):
print(kmeans.labels_[i]," - ", L[i])
print(kmeans.cluster_centers_)
Duyệt từng cụm một sau đó in các cụm vữa phân được lên.
n_row = 6
n_col=6
for i in range(4):
_, axs = plt.subplots(n_row, n_col, figsize=(7, 7))
axs = axs.flatten()
for img, ax in zip(L[ kmeans.labels_ == i][:36], axs):
ax.imshow(mpimg.imread(os.path.join(c_data_path,img)))
plt.tight_layout()
plt.show()