Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Hướng dẫn rõ ràng về K-Means Clustering với Scikit-Learn

Giới thiệu

K-Means cụm là một trong những thuật toán học máy không giám sát được sử dụng rộng rãi nhất, tạo thành các cụm dữ liệu dựa trên sự giống nhau giữa các trường hợp dữ liệu.

Trong hướng dẫn này, trước tiên chúng ta sẽ xem xét một ví dụ đơn giản để hiểu cách hoạt động của thuật toán K-Means trước khi triển khai nó bằng Scikit-Learn. Sau đó, chúng ta sẽ thảo luận về cách xác định số lượng cụm (K) trong K-Means và cũng bao gồm các chỉ số khoảng cách, phương sai và ưu nhược điểm của K-Means.

Động lực

Hãy tưởng tượng tình huống sau đây. Một ngày nọ, khi đi dạo quanh khu phố, bạn nhận thấy có 10 cửa hàng tiện lợi và bắt đầu tự hỏi cửa hàng nào giống nhau - gần nhau hơn ở những khu vực lân cận. Trong khi tìm cách trả lời câu hỏi đó, bạn đã bắt gặp một cách tiếp cận thú vị chia các cửa hàng thành các nhóm dựa trên tọa độ của chúng trên bản đồ.

Ví dụ: nếu một cửa hàng cách 5 km về phía Tây và 3 km về phía Bắc - bạn sẽ chỉ định (5, 3) tọa độ của nó và biểu diễn nó dưới dạng đồ thị. Hãy vẽ sơ đồ điểm đầu tiên này để hình dung những gì đang xảy ra:

import matplotlib.pyplot as plt

plt.title("Store With Coordinates (5, 3)")
plt.scatter(x=5, y=3)

Đây chỉ là điểm đầu tiên, vì vậy chúng tôi có thể có ý tưởng về cách chúng tôi có thể đại diện cho một cửa hàng. Giả sử chúng ta đã có 10 tọa độ cho 10 cửa hàng được thu thập. Sau khi tổ chức chúng trong một numpy mảng, chúng tôi cũng có thể vẽ biểu đồ vị trí của chúng:

import numpy as np

points = np.array([[5, 3], [10, 15], [15, 12], [24, 10], [30, 45], [85, 70], [71, 80], [60, 78], [55, 52],[80, 91]])

xs = points[:,0] 
ys = points[:,1]  

plt.title("10 Stores Coordinates")
plt.scatter(x=xs, y=ys)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Cách triển khai thủ công thuật toán K-Means

Bây giờ chúng ta có thể xem xét 10 cửa hàng trên một biểu đồ, và vấn đề chính là tìm cách nào để chúng có thể được chia thành các nhóm khác nhau dựa trên khoảng cách? Chỉ cần nhìn sơ qua biểu đồ, chúng ta có thể nhận thấy hai nhóm cửa hàng - một là các điểm dưới cùng bên trái, và một là các điểm trên bên phải. Có lẽ, chúng ta thậm chí có thể phân biệt hai điểm đó ở giữa như một nhóm riêng biệt - do đó tạo ra ba nhóm khác nhau.

Trong phần này, chúng ta sẽ xem xét quá trình phân nhóm các điểm theo cách thủ công - chia chúng thành một số nhóm nhất định. Bằng cách đó, về cơ bản, chúng tôi sẽ xem xét cẩn thận tất cả các bước của Thuật toán phân cụm K-Means. Đến cuối phần này, bạn sẽ hiểu được cả trực quan và thực tế về tất cả các bước được thực hiện trong quá trình phân cụm K-Means. Sau đó, chúng tôi sẽ ủy quyền nó cho Scikit-Learn.

Cách tốt nhất để xác định nếu có hai hoặc ba nhóm điểm là gì? Một cách đơn giản là chỉ cần chọn một số nhóm - ví dụ, hai nhóm - và sau đó cố gắng nhóm các điểm dựa trên lựa chọn đó.

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Giả sử chúng tôi đã quyết định có hai nhóm của các cửa hàng của chúng tôi (điểm). Bây giờ, chúng ta cần tìm cách hiểu những điểm nào thuộc nhóm nào. Điều này có thể được thực hiện bằng cách chọn một điểm để đại diện nhóm 1 và một để đại diện nhóm 2. Những điểm đó sẽ được sử dụng làm tham chiếu khi đo khoảng cách từ tất cả các điểm khác đến mỗi nhóm.

Theo cách đó, hãy nói điểm (5, 3) cuối cùng thuộc nhóm 1 và điểm (79, 60) cho nhóm 2. Khi cố gắng chỉ định một điểm mới (6, 3) cho các nhóm, chúng ta cần đo khoảng cách của nó đến hai điểm đó. Trong trường hợp của điểm (6, 3) is gần gũi hơn đến (5, 3), do đó nó thuộc nhóm được đại diện bởi điểm đó - nhóm 1. Bằng cách này, chúng ta có thể dễ dàng nhóm tất cả các điểm vào các nhóm tương ứng.

Trong ví dụ này, ngoài việc xác định số lượng nhóm (cụm) - chúng tôi cũng đang chọn một số điểm để trở thành tài liệu tham khảo khoảng cách cho các điểm mới của mỗi nhóm.

Đó là ý tưởng chung để hiểu sự tương đồng giữa các cửa hàng của chúng tôi. Hãy đưa nó vào thực tế - trước tiên chúng ta có thể chọn hai điểm tham chiếu tại ngẫu nhiên. Điểm tham chiếu của nhóm 1 sẽ được (5, 3) và điểm tham chiếu của nhóm 2 sẽ được (10, 15). Chúng tôi có thể chọn cả hai điểm numpy mảng bởi [0][1] lập chỉ mục và lưu trữ chúng trong g1 (nhóm 1) và g2 (nhóm 2) các biến:

g1 = points[0]
g2 = points[1]

Sau khi thực hiện, chúng ta cần tính khoảng cách từ tất cả các điểm khác đến các điểm tham chiếu đó. Điều này đặt ra một câu hỏi quan trọng - làm thế nào để đo khoảng cách đó. Về cơ bản chúng ta có thể sử dụng bất kỳ thước đo khoảng cách nào, nhưng với mục đích của hướng dẫn này, hãy sử dụng Euclidean Distance_.

Có thể hữu ích khi biết rằng số đo khoảng cách Euclid dựa trên định lý Pythagoras:

$$
c ^ 2 = a ^ 2 + b ^ 2
$$

Khi thích nghi với các điểm trong mặt phẳng - (a1, b1)(a2, b2), công thức trước đó trở thành:

$$
c ^ 2 = (a2-a1) ^ 2 + (b2-b1) ^ 2
$$

Khoảng cách sẽ là căn bậc hai của c, vì vậy chúng ta cũng có thể viết công thức dưới dạng:

$$
euclidean_ {dist} = sqrt [2] [(a2 - a1) ^ 2 + (b2 - b1) ^ 2)]
$$

Lưu ý: Bạn cũng có thể tổng quát công thức khoảng cách Euclide cho các điểm đa chiều. Ví dụ, trong không gian ba chiều, các điểm có ba tọa độ - công thức của chúng tôi phản ánh điều đó theo cách sau:
$$
euclidean_ {dist} = sqrt [2] [(a2 - a1) ^ 2 + (b2 - b1) ^ 2 + (c2 - c1) ^ 2)]
$$
Nguyên tắc tương tự được tuân theo bất kể số lượng chiều của không gian mà chúng ta đang vận hành.

Cho đến nay, chúng tôi đã chọn các điểm để đại diện cho các nhóm và chúng tôi biết cách tính khoảng cách. Bây giờ, chúng ta hãy đặt khoảng cách và các nhóm lại với nhau bằng cách gán mỗi điểm cửa hàng đã thu thập của chúng ta cho một nhóm.

Để hình dung rõ hơn về điều đó, chúng tôi sẽ khai báo ba danh sách. Người đầu tiên lưu trữ điểm của nhóm đầu tiên - points_in_g1. Người thứ hai lưu trữ điểm từ nhóm 2 - points_in_g2, và điều cuối cùng - group, Để nhãn những điểm như một trong hai 1 (thuộc nhóm 1) hoặc 2 (thuộc nhóm 2):

points_in_g1 = []
points_in_g2 = []
group = []

Bây giờ chúng ta có thể lặp lại các điểm của mình và tính toán khoảng cách Euclid giữa chúng và mỗi tham chiếu nhóm của chúng ta. Mỗi điểm sẽ được gần gũi hơn cho một trong hai nhóm - dựa trên nhóm nào gần nhất, chúng tôi sẽ chỉ định từng điểm cho danh sách tương ứng, đồng thời thêm 1 or 2 đến group danh sách:

for p in points:
    x1, y1 = p[0], p[1]
    euclidean_distance_g1 = np.sqrt((g1[0] - x1)**2 + (g1[1] - y1)**2)
    euclidean_distance_g2 = np.sqrt((g2[0] - x1)**2 + (g2[1] - y1)**2)
    if euclidean_distance_g1 < euclidean_distance_g2:
        points_in_g1.append(p)
        group.append('1')
    else:
        points_in_g2.append(p)
        group.append('2')

Hãy xem kết quả của lần lặp này để xem điều gì đã xảy ra:

print(f'points_in_g1:{points_in_g1}n 
npoints_in_g2:{points_in_g2}n 
ngroup:{group}')

Kết quả là:

points_in_g1:[array([5, 3])]
 
points_in_g2:[array([10, 15]), array([15, 12]), 
              array([24, 10]), array([30, 45]), 
              array([85, 70]), array([71, 80]),
              array([60, 78]), array([55, 52]), 
              array([80, 91])]
 
group:[1, 2, 2, 2, 2, 2, 2, 2, 2, 2] 

Chúng tôi cũng có thể vẽ biểu đồ kết quả phân nhóm, với các màu khác nhau dựa trên các nhóm được chỉ định, sử dụng Seaborn's scatterplot() với group như là một hue tranh luận:

import seaborn as sns

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Rõ ràng là chỉ có điểm đầu tiên của chúng tôi được gán cho nhóm 1, và tất cả các điểm khác được gán cho nhóm 2. Kết quả đó khác với những gì chúng tôi đã hình dung lúc đầu. Xem xét sự khác biệt giữa kết quả của chúng tôi và kỳ vọng ban đầu của chúng tôi - có cách nào chúng tôi có thể thay đổi điều đó không? Có vẻ như có!

Một cách tiếp cận là lặp lại quá trình và chọn các điểm khác nhau để làm tài liệu tham khảo của các nhóm. Điều này sẽ thay đổi kết quả của chúng tôi, hy vọng, phù hợp hơn với những gì chúng tôi đã hình dung lúc đầu. Lần thứ hai này, chúng tôi có thể chọn chúng không phải ngẫu nhiên như chúng tôi đã làm trước đây, mà bằng cách lấy nghĩa là trong số tất cả các điểm đã được nhóm của chúng tôi. Bằng cách đó, những điểm mới đó có thể được đặt ở giữa các nhóm tương ứng.

Ví dụ, nếu nhóm thứ hai chỉ có điểm (10, 15), (30, 45). Mới trung tâm điểm sẽ là (10 + 30)/2(15+45)/2 - bằng (20, 30).

Vì chúng tôi đã đưa kết quả của mình vào danh sách, nên trước tiên chúng tôi có thể chuyển đổi chúng thành numpy mảng, chọn xs, ys của chúng và sau đó lấy nghĩa là:

g1_center = [np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()]
g2_center = [np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()]
g1_center, g2_center

Khuyên bảo: Thử sử dụng numpy và mảng NumPy càng nhiều càng tốt. Chúng được tối ưu hóa để có hiệu suất tốt hơn và đơn giản hóa nhiều phép toán đại số tuyến tính. Bất cứ khi nào bạn đang cố gắng giải một số bài toán đại số tuyến tính, bạn chắc chắn nên xem numpy tài liệu để kiểm tra xem có bất kỳ numpy phương pháp được thiết kế để giải quyết vấn đề của bạn. Cơ hội là có!

Để giúp lặp lại quá trình với các điểm trung tâm mới của chúng tôi, hãy chuyển đổi mã trước đó của chúng tôi thành một hàm, thực thi nó và xem liệu có bất kỳ thay đổi nào về cách các điểm được nhóm lại không:

def assigns_points_to_two_groups(g1_center, g2_center):
    points_in_g1 = []
    points_in_g2 = []
    group = []

    for p in points:
        x1, y1 = p[0], p[1]
        euclidean_distance_g1 = np.sqrt((g1_center[0] - x1)**2 + (g1_center[1] - y1)**2)
        euclidean_distance_g2 = np.sqrt((g2_center[0] - x1)**2 + (g2_center[1] - y1)**2)
        if euclidean_distance_g1 < euclidean_distance_g2:
            points_in_g1.append(p)
            group.append(1)
        else:
            points_in_g2.append(p)
            group.append(2)
    return points_in_g1, points_in_g2, group

Lưu ý: Nếu bạn nhận thấy rằng bạn tiếp tục lặp đi lặp lại cùng một mã, bạn nên gói mã đó thành một hàm riêng biệt. Nó được coi là phương pháp hay nhất để tổ chức mã thành các hàm, đặc biệt vì chúng tạo điều kiện thuận lợi cho việc kiểm tra. Việc kiểm tra và tách đoạn mã dễ dàng hơn một đoạn mã đầy đủ không có bất kỳ chức năng nào.

Hãy gọi hàm và lưu trữ kết quả của nó trong points_in_g1, points_in_g2group biến:

points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
points_in_g1, points_in_g2, group

Và cũng vẽ biểu đồ phân tán với các điểm được tô màu để hình dung sự phân chia nhóm:

sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Có vẻ như nhóm các điểm của chúng ta là trở nên tốt hơn. Tuy nhiên, có hai điểm ở giữa biểu đồ có thể được gán cho một trong hai nhóm khi xem xét khoảng cách của chúng với cả hai nhóm. Thuật toán mà chúng tôi đã phát triển cho đến nay sẽ gán cả hai điểm đó cho nhóm thứ hai.

Điều này có nghĩa là chúng ta có thể lặp lại quá trình một lần nữa bằng cách sử dụng phương tiện của Xs và Y, tạo ra hai điểm trung tâm mới (centroid) cho các nhóm của chúng tôi và chỉ định lại chúng dựa trên khoảng cách.

Hãy cũng tạo một chức năng để cập nhật các centroid. Toàn bộ quá trình bây giờ có thể được rút gọn thành nhiều lệnh gọi của hàm đó:

def updates_centroids(points_in_g1, points_in_g2):
    g1_center = np.array(points_in_g1)[:, 0].mean(), np.array(points_in_g1)[:, 1].mean()
    g2_center = np.array(points_in_g2)[:, 0].mean(), np.array(points_in_g2)[:, 1].mean()
    return g1_center, g2_center

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Lưu ý rằng sau lần lặp thứ ba này, mỗi điểm bây giờ thuộc về các cụm khác nhau. Có vẻ như kết quả đang trở nên tốt hơn - chúng ta hãy làm điều đó một lần nữa. Bây giờ sẽ đến lần lặp thứ tư phương pháp của chúng tôi:

g1_center, g2_center = updates_centroids(points_in_g1, points_in_g2)
points_in_g1, points_in_g2, group = assigns_points_to_two_groups(g1_center, g2_center)
sns.scatterplot(x=points[:, 0], y=points[:, 1], hue=group)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Lần thứ tư này chúng tôi có cùng một kết quả như phần trước. Vì vậy, có vẻ như các điểm của chúng tôi sẽ không thay đổi nhóm nữa, kết quả của chúng tôi đã đạt đến một số loại ổn định - nó đã đến trạng thái không thể thay đổi, hoặc hội tụ. Bên cạnh đó, chúng tôi có kết quả giống hệt như chúng tôi đã hình dung cho 2 nhóm. Chúng tôi cũng có thể xem liệu sự phân chia đã đạt được này có ý nghĩa hay không.

Hãy nhanh chóng tóm tắt lại những gì chúng tôi đã làm cho đến nay. Về mặt địa lý, chúng tôi đã chia 10 cửa hàng của mình thành hai phần - một phần ở các khu vực phía tây nam và những cửa hàng khác ở phía đông bắc. Có thể thú vị khi thu thập thêm dữ liệu ngoài những gì chúng tôi đã có - doanh thu, số lượng khách hàng hàng ngày và nhiều dữ liệu khác. Bằng cách đó, chúng tôi có thể tiến hành một phân tích phong phú hơn và có thể tạo ra nhiều kết quả thú vị hơn.

Các nghiên cứu theo cụm như thế này có thể được tiến hành khi một thương hiệu đã có tên tuổi muốn chọn một khu vực để mở một cửa hàng mới. Trong trường hợp đó, có nhiều biến số khác được xem xét ngoài vị trí.

Tất cả điều này liên quan gì đến thuật toán K-Means?

Trong khi làm theo các bước này, bạn có thể tự hỏi chúng phải làm gì với thuật toán K-Means. Quá trình chúng tôi đã tiến hành cho đến nay là Thuật toán K-Means. Tóm lại, chúng tôi đã xác định số lượng nhóm / cụm, chọn ngẫu nhiên các điểm ban đầu và cập nhật các trọng tâm trong mỗi lần lặp cho đến khi các cụm hội tụ. Về cơ bản, chúng tôi đã thực hiện toàn bộ thuật toán bằng tay - tiến hành cẩn thận từng bước.

Sản phẩm K trong K-Means đến từ số lượng các cụm cần phải được thiết lập trước khi bắt đầu quá trình lặp lại. Trong trường hợp của chúng ta K = 2. Đặc điểm này đôi khi được coi là tiêu cực xem xét có các phương pháp phân cụm khác, chẳng hạn như Phân cụm theo thứ bậc, không cần phải có một số lượng cụm cố định trước đó.

Do việc sử dụng các phương tiện, K-means cũng trở thành nhạy cảm với các giá trị ngoại lai và giá trị cực đoan - chúng tăng cường khả năng thay đổi và khiến các trung tâm của chúng ta khó đóng vai trò của chúng hơn. Vì vậy, hãy ý thức về sự cần thiết phải thực hiện giá trị cực đoan và phân tích ngoại lệ trước khi tiến hành phân cụm bằng thuật toán K-Means.

Ngoài ra, hãy lưu ý rằng các điểm của chúng ta được phân đoạn thành các phần thẳng, không có đường cong khi tạo các cụm. Đó cũng có thể là một nhược điểm của thuật toán K-Means.

Lưu ý: Khi bạn cần nó linh hoạt hơn và thích ứng với hình elip và các hình dạng khác, hãy thử sử dụng mô hình hỗn hợp Gaussian K-mean tổng quát. Mô hình này có thể thích ứng với các cụm phân đoạn hình elip.

K-Means cũng có nhiều lợi thế! Nó hoạt động tốt trên bộ dữ liệu lớn có thể trở nên khó xử lý nếu bạn đang sử dụng một số loại thuật toán phân cụm phân cấp. Nó cũng đảm bảo sự hội tụ, và có thể dễ dàng khái quátthích ứng. Bên cạnh đó, nó có lẽ là thuật toán phân cụm được sử dụng nhiều nhất.

Bây giờ chúng ta đã xem qua tất cả các bước được thực hiện trong thuật toán K-Means và hiểu tất cả ưu và nhược điểm của nó, cuối cùng chúng ta có thể triển khai K-Means bằng cách sử dụng thư viện Scikit-Learn.

Cách triển khai sử dụng thuật toán K-Means scikit-học

Để kiểm tra lại kết quả của chúng tôi, hãy thực hiện lại quy trình này, nhưng bây giờ sử dụng 3 dòng mã với sklearn:

from sklearn.cluster import KMeans


kmeans = KMeans(n_clusters=2, random_state=42) 
kmeans.fit(points)
kmeans.labels_

Ở đây, các nhãn giống với các nhóm trước của chúng tôi. Hãy nhanh chóng vẽ sơ đồ kết quả:

sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Cốt truyện kết quả giống với cốt truyện từ phần trước.

Xem hướng dẫn thực hành, thực tế của chúng tôi để học Git, với các phương pháp hay nhất, các tiêu chuẩn được ngành công nghiệp chấp nhận và bảng lừa đảo đi kèm. Dừng lệnh Googling Git và thực sự học nó!

Lưu ý: Chỉ cần nhìn vào cách chúng tôi đã thực hiện thuật toán K-Means bằng cách sử dụng Scikit-Learn có thể cho bạn ấn tượng rằng đây là điều không cần bàn cãi và bạn không cần phải lo lắng quá nhiều về nó. Chỉ 3 dòng mã thực hiện tất cả các bước mà chúng ta đã thảo luận trong phần trước khi chúng ta xem qua từng bước thuật toán K-Means. Nhưng mà, Ma quỷ là trong các chi tiết trong trường hợp này! Nếu bạn không hiểu tất cả các bước và giới hạn của thuật toán, rất có thể bạn sẽ gặp phải tình huống mà thuật toán K-Means cho bạn kết quả mà bạn không mong đợi.

Với Scikit-Learn, bạn cũng có thể khởi tạo K-Means để hội tụ nhanh hơn bằng cách thiết lập init='k-means++' tranh luận. Nói một cách rộng rãi hơn, K-Means ++ vẫn chọn k các trung tâm cụm ban đầu một cách ngẫu nhiên theo một phân bố đồng đều. Sau đó, mỗi trung tâm cụm tiếp theo được chọn từ các điểm dữ liệu còn lại không chỉ bằng cách tính toán một thước đo khoảng cách - mà bằng cách sử dụng xác suất. Sử dụng xác suất tăng tốc thuật toán và rất hữu ích khi xử lý các tập dữ liệu rất lớn.

Phương pháp khuỷu tay - Chọn số lượng nhóm tốt nhất

Càng xa càng tốt! Chúng tôi đã tập hợp 10 cửa hàng dựa trên khoảng cách Euclid giữa các điểm và centroid. Nhưng còn hai điểm ở giữa biểu đồ khó phân cụm hơn một chút thì sao? Họ không thể thành lập một nhóm riêng biệt? Có phải chúng tôi đã thực sự mắc sai lầm khi chọn K = 2 các nhóm? Có lẽ chúng tôi thực sự đã có K = 3 các nhóm? Chúng tôi thậm chí có thể có nhiều hơn ba nhóm và không nhận thức được điều đó.

Câu hỏi được hỏi ở đây là cách xác định số lượng nhóm (K) trong K-Means. Để trả lời câu hỏi đó, chúng ta cần hiểu liệu sẽ có một cụm "tốt hơn" cho một giá trị khác của K.

Cách đơn giản để tìm ra điều đó là nhóm các điểm với các giá trị khác nhau của K, vì vậy đối với K = 2, K = 3, K = 4, v.v.:

for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 

Tuy nhiên, nhóm các điểm cho các Ks cô đơn sẽ không đủ để hiểu liệu chúng tôi đã chọn giá trị lý tưởng cho K. Chúng tôi cần một cách để đánh giá chất lượng phân nhóm cho từng K chúng tôi đã chọn.

Tính toán thủ công Trong Cụm Tổng bình phương (WCSS)

Đây là nơi lý tưởng để giới thiệu thước đo về mức độ các điểm nhóm của chúng ta gần nhau. Về cơ bản, nó mô tả bao nhiêu không đúng chúng tôi có bên trong một cụm duy nhất. Biện pháp này được gọi là Trong Cụm Tổng các Hình vuông, hoặc là vệ sinh gọi tắt là. WCSS càng nhỏ, các điểm của chúng ta càng gần nhau, do đó chúng ta có một cụm được hình thành tốt hơn. Công thức WCSS có thể được sử dụng cho bất kỳ số cụm nào:

$$
WCSS = sum (Pi_1 - Centroid_1) ^ 2 + cdots + sum (Pi_n - Centroid_n) ^ 2
$$

Lưu ý: Trong hướng dẫn này, chúng tôi đang sử dụng Khoảng cách Euclide để lấy centroid, nhưng cũng có thể sử dụng các thước đo khoảng cách khác, chẳng hạn như Manhattan.

Bây giờ chúng ta có thể giả sử rằng chúng ta đã chọn có hai cụm và cố gắng triển khai WCSS để hiểu rõ hơn WCSS là gì và cách sử dụng nó. Như công thức đã nêu, chúng ta cần tính tổng bình phương sự khác biệt giữa tất cả các điểm cụm và tâm. Vì vậy, nếu điểm đầu tiên của chúng ta từ nhóm đầu tiên là (5, 3) và trung tâm cuối cùng của chúng tôi (sau khi hội tụ) của nhóm đầu tiên là (16.8, 17.0), WCSS sẽ là:

$$
WCSS = sum ((5,3) - (16.8, 17.0)) ^ 2
$$

$$
WCSS = sum ((5-16.8) + (3-17.0)) ^ 2
$$

$$
WCSS = sum ((- 11.8) + (-14.0)) ^ 2
$$

$$
WCSS = sum ((- 25.8)) ^ 2
$$

$$
WCSS = 335.24
$$

Ví dụ này minh họa cách chúng tôi tính toán WCSS cho một điểm từ cụm. Nhưng cụm thường chứa nhiều hơn một điểm và chúng ta cần xem xét tất cả chúng khi tính toán WCSS. Chúng tôi sẽ làm điều đó bằng cách xác định một hàm nhận một cụm điểm và trọng tâm, và trả về tổng các bình phương:

def sum_of_squares(cluster, centroid):
    squares = []
    for p in cluster:
        squares.append((p - centroid)**2)
        ss = np.array(squares).sum()
    return ss

Bây giờ chúng ta có thể nhận được tổng các hình vuông cho mỗi cụm:

g1 = sum_of_squares(points_in_g1, g1_center)
g2 = sum_of_squares(points_in_g2, g2_center)

Và tổng hợp các kết quả để có được tổng vệ sinh:

g1 + g2

Kết quả này trong:

2964.3999999999996

Vì vậy, trong trường hợp của chúng tôi, khi K bằng 2, tổng WCSS là 2964.39. Bây giờ, chúng ta có thể chuyển đổi K và tính toán WCSS cho tất cả chúng. Bằng cách đó, chúng ta có thể có được cái nhìn sâu sắc về những gì K chúng ta nên chọn để làm cho phân cụm của chúng ta hoạt động tốt nhất.

Tính vệ sinh Sử dụng scikit-học

May mắn thay, chúng tôi không cần phải tính toán WCSS theo cách thủ công cho mỗi K. Sau khi thực hiện phân cụm K-Means cho các cụm nuber đã cho, chúng ta có thể lấy WCSS của nó bằng cách sử dụng inertia_ thuộc tính. Bây giờ, chúng ta có thể quay lại K-Means của chúng ta for vòng lặp, sử dụng nó để trao đổi với số lượng cụm và liệt kê các giá trị WCSS tương ứng:

wcss = [] 
for number_of_clusters in range(1, 11): 
    kmeans = KMeans(n_clusters = number_of_clusters, random_state = 42)
    kmeans.fit(points) 
    wcss.append(kmeans.inertia_)
wcss

Lưu ý rằng giá trị thứ hai trong danh sách, hoàn toàn giống với giá trị mà chúng tôi đã tính toán trước đây cho K = 2:

[18272.9, # For k=1 
 2964.3999999999996, # For k=2
 1198.75, # For k=3
 861.75,
 570.5,
 337.5,
 175.83333333333334,
 79.5,
 17.0,
 0.0]

Để hình dung những kết quả đó, hãy vẽ biểu đồ Ks cùng với các giá trị WCSS:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Có sự gián đoạn trong một cốt truyện khi x = 2, một điểm thấp trong dòng và một điểm thấp hơn nữa khi x = 3. Lưu ý rằng nó nhắc nhở chúng ta về hình dạng của một khuỷu tay. Bằng cách vẽ biểu đồ K cùng với WCSS, chúng tôi đang sử dụng Phương pháp khuỷu tay để chọn số lượng Ks. Và K được chọn chính xác là điểm khuỷu tay thấp nhất, vì vậy, nó sẽ là 3 thay vì 2, trong trường hợp của chúng ta:

ks = [1, 2, 3, 4, 5 , 6 , 7 , 8, 9, 10]
plt.plot(ks, wcss);
plt.axvline(3, linestyle='--', color='r')

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Chúng tôi có thể chạy lại thuật toán cụm K-Means để xem dữ liệu của chúng tôi trông như thế nào với ba cụm:

kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(points)
sns.scatterplot(x = points[:,0], y = points[:,1], hue=kmeans.labels_)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Chúng tôi đã hài lòng với hai cụm, nhưng theo phương pháp khuỷu tay, ba cụm sẽ phù hợp hơn với dữ liệu của chúng tôi. Trong trường hợp này, chúng ta sẽ có ba loại cửa hàng thay vì hai. Trước khi sử dụng phương pháp khuỷu tay, chúng tôi nghĩ về các cụm cửa hàng phía Tây Nam và Đông Bắc, bây giờ chúng tôi cũng có các cửa hàng ở trung tâm. Có lẽ đó có thể là một vị trí tốt để mở một cửa hàng khác vì gần đó sẽ ít cạnh tranh hơn.

Các biện pháp chất lượng cụm thay thế

Ngoài ra còn có các biện pháp khác có thể được sử dụng khi đánh giá chất lượng cụm:

  • Điểm Silhouette - không chỉ phân tích khoảng cách giữa các điểm trong cụm mà còn giữa các cụm với nhau
  • Giữa các cụm Tổng hình vuông (BCSS) - chỉ số bổ sung cho WCSS
  • Lỗi tổng bình phương (ESS)
  • Bán kính tối đa - đo khoảng cách lớn nhất từ ​​một điểm đến tâm của nó
  • Bán kính trung bình - tổng khoảng cách lớn nhất từ ​​một điểm đến tâm của nó chia cho số cụm.

Bạn nên thử nghiệm và tìm hiểu từng người trong số họ vì tùy thuộc vào vấn đề, một số lựa chọn thay thế có thể áp dụng hơn các chỉ số được sử dụng rộng rãi nhất (WCSS và Điểm hình bóng).

Cuối cùng, như với nhiều thuật toán khoa học dữ liệu, chúng tôi muốn giảm phương sai bên trong mỗi cụm và tối đa hóa phương sai giữa các cụm khác nhau. Vì vậy, chúng tôi có nhiều cụm được xác định và phân tách.

Áp dụng K-Means trên một tập dữ liệu khác

Hãy sử dụng những gì chúng ta đã học được trên một tập dữ liệu khác. Lần này, chúng tôi sẽ cố gắng tìm các nhóm rượu tương tự.

Lưu ý: Bạn có thể tải xuống bộ dữ liệu tại đây.

Chúng tôi bắt đầu bằng cách nhập pandas để đọc wine-clustering CSV (Các giá trị được phân tách bằng dấu phẩy) tập tin vào một Dataframe kết cấu:

import pandas as pd

df = pd.read_csv('wine-clustering.csv')

Sau khi tải nó, chúng ta hãy xem năm bản ghi dữ liệu đầu tiên với head() phương pháp:

df.head()

Kết quả này trong:

	Alcohol 	Malic_Acid 	Ash 	Ash_Alcanity 	Magnesium 	Total_Phenols 	Flavanoids 	Nonflavanoid_Phenols 	Proanthocyanins 	Color_Intensity 	Hue 	OD280 	Proline
0 	14.23 		1.71 		2.43 	15.6 			127 		2.80 			3.06 		0.28 					2.29 				5.64 				1.04 	3.92 	1065
1 	13.20 		1.78 		2.14 	11.2 			100 		2.65 			2.76 		0.26 					1.28 				4.38 				1.05 	3.40 	1050
2 	13.16 		2.36 		2.67 	18.6 			101 		2.80 			3.24 		0.30 					2.81 				5.68 				1.03 	3.17 	1185
3 	14.37 		1.95 		2.50 	16.8 			113 		3.85 			3.49 		0.24 					2.18 				7.80 				0.86 	3.45 	1480
4 	13.24 		2.59 		2.87 	21.0 			118 		2.80 			2.69 		0.39 					1.82 				4.32 				1.04 	2.93 	735

Chúng tôi có nhiều phép đo các chất có trong rượu vang. Ở đây, chúng ta cũng sẽ không cần phải chuyển đổi các cột phân loại vì tất cả chúng đều là số. Bây giờ, chúng ta hãy xem các thống kê mô tả với describe() phương pháp:

df.describe().T 

Bảng mô tả:

 						count 	mean 		std 		min 	25% 	50% 	75% 		max
Alcohol 				178.0 	13.000618 	0.811827 	11.03 	12.3625 13.050 	13.6775 	14.83
Malic_Acid 				178.0 	2.336348 	1.117146 	0.74 	1.6025 	1.865 	3.0825 		5.80
Ash 					178.0 	2.366517 	0.274344 	1.36 	2.2100 	2.360 	2.5575 		3.23
Ash_Alcanity 			178.0 	19.494944 	3.339564 	10.60 	17.2000 19.500 	21.5000 	30.00
Magnesium 				178.0 	99.741573 	14.282484 	70.00 	88.0000 98.000 	107.0000 	162.00
Total_Phenols 			178.0 	2.295112 	0.625851 	0.98 	1.7425 	2.355 	2.8000 		3.88
Flavanoids 				178.0 	2.029270 	0.998859 	0.34 	1.2050 	2.135 	2.8750 		5.08
Nonflavanoid_Phenols 	178.0 	0.361854 	0.124453 	0.13 	0.2700 	0.340 	0.4375 		0.66
Proanthocyanins 		178.0 	1.590899 	0.572359 	0.41 	1.2500 	1.555 	1.9500 		3.58
Color_Intensity 		178.0 	5.058090 	2.318286 	1.28 	3.2200 	4.690 	6.2000 		13.00
Hue 					178.0 	0.957449 	0.228572 	0.48 	0.7825 	0.965 	1.1200 		1.71
OD280 					178.0 	2.611685 	0.709990 	1.27 	1.9375 	2.780 	3.1700 		4.00
Proline 				178.0 	746.893258 	314.907474 	278.00 	500.500 673.500 985.0000 	1680.00

Bằng cách nhìn vào bảng, rõ ràng là có một số sự thay đổi trong dữ liệu - đối với một số cột như Alchool có nhiều hơn nữa, và cho những người khác, chẳng hạn như Malic_Acid, ít hơn. Bây giờ chúng tôi có thể kiểm tra xem có bất kỳ null, hoặc là NaN giá trị trong tập dữ liệu của chúng tôi:

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 178 entries, 0 to 177
Data columns (total 13 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   Alcohol               178 non-null    float64
 1   Malic_Acid            178 non-null    float64
 2   Ash                   178 non-null    float64
 3   Ash_Alcanity          178 non-null    float64
 4   Magnesium             178 non-null    int64  
 5   Total_Phenols         178 non-null    float64
 6   Flavanoids            178 non-null    float64
 7   Nonflavanoid_Phenols  178 non-null    float64
 8   Proanthocyanins       178 non-null    float64
 9   Color_Intensity       178 non-null    float64
 10  Hue                   178 non-null    float64
 11  OD280                 178 non-null    float64
 12  Proline               178 non-null    int64  
dtypes: float64(11), int64(2)
memory usage: 18.2 KB

Không cần phải giảm hoặc nhập dữ liệu, vì không có giá trị trống trong tập dữ liệu. Chúng ta có thể sử dụng Seaborn pairplot() để xem phân phối dữ liệu và kiểm tra xem tập dữ liệu có tạo thành các cặp cột có thể thú vị cho việc phân nhóm hay không:

sns.pairplot(df)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Bằng cách nhìn vào cặp lô, hai cột có vẻ hứa hẹn cho các mục đích phân nhóm - AlcoholOD280 (là một phương pháp để xác định nồng độ protein trong rượu vang). Có vẻ như có 3 cụm riêng biệt trên các lô kết hợp hai trong số chúng.

Có những cột khác dường như cũng tương quan với nhau. Đáng chú ý nhất AlcoholTotal_PhenolsAlcoholFlavanoids. Chúng có mối quan hệ tuyến tính tuyệt vời có thể được quan sát thấy trong cặp lô.

Vì trọng tâm của chúng ta đang phân nhóm với K-Means, hãy chọn một cặp cột, giả sử AlcoholOD280và kiểm tra phương pháp khuỷu tay cho tập dữ liệu này.

Lưu ý: Khi sử dụng nhiều cột hơn của tập dữ liệu, sẽ có nhu cầu vẽ biểu đồ theo 3 chiều hoặc giảm dữ liệu xuống các thành phần chính (sử dụng PCA). Đây là cách tiếp cận hợp lệ và phổ biến hơn, chỉ cần đảm bảo chọn các thành phần chính dựa trên mức độ chúng giải thích và lưu ý rằng khi giảm kích thước dữ liệu, sẽ có một số mất mát thông tin - do đó, âm mưu là một sự xấp xỉ của dữ liệu thực chứ không phải dữ liệu thực sự như thế nào.

Hãy vẽ biểu đồ phân tán với hai cột đó được đặt làm trục của nó để xem xét kỹ hơn các điểm chúng ta muốn chia thành các nhóm:

sns.scatterplot(data=df, x='OD280', y='Alcohol')

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Bây giờ chúng ta có thể xác định các cột của mình và sử dụng phương pháp khuỷu tay để xác định số lượng các cụm. Chúng tôi cũng sẽ bắt đầu thuật toán với kmeans++ chỉ để đảm bảo rằng nó hội tụ nhanh hơn:

values = df[['OD280', 'Alcohol']]

wcss_wine = [] 
for i in range(1, 11): 
    kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
    kmeans.fit(values) 
    wcss_wine.append(kmeans.inertia_)

Chúng tôi đã tính toán WCSS, vì vậy chúng tôi có thể vẽ biểu đồ kết quả:

clusters_wine = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(clusters_wine, wcss_wine)
plt.axvline(3, linestyle='--', color='r')

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Theo phương pháp cùi chỏ, chúng ta nên có 3 cụm ở đây. Đối với bước cuối cùng, hãy tập hợp các điểm của chúng ta thành 3 cụm và vẽ biểu đồ của các cụm đó được xác định bằng màu sắc:

kmeans_wine = KMeans(n_clusters=3, random_state=42)
kmeans_wine.fit(values)
sns.scatterplot(x = values['OD280'], y = values['Alcohol'], hue=kmeans_wine.labels_)

Hướng dẫn dứt khoát về phân cụm K-Means với trí thông minh dữ liệu PlatoBlockchain của Scikit-Learn. Tìm kiếm dọc. Ái.

Chúng ta có thể thấy các cụm 0, 12 trong đồ thị. Dựa trên phân tích của chúng tôi, nhóm 0 có rượu vang có hàm lượng protein cao hơn và độ cồn thấp hơn, nhóm 1 có rượu vang có nồng độ cồn cao hơn và protein thấp, và nhóm 2 có cả protein cao và độ cồn cao trong rượu vang của nó.

Đây là một tập dữ liệu rất thú vị và tôi khuyến khích bạn đi sâu hơn vào phân tích bằng cách nhóm dữ liệu sau khi chuẩn hóa và PCA - cũng bằng cách giải thích kết quả và tìm các kết nối mới.

Kết luận

K-nghĩa clustering là một thuật toán học máy không giám sát đơn giản nhưng rất hiệu quả để phân cụm dữ liệu. Nó phân cụm dữ liệu dựa trên khoảng cách Euclid giữa các điểm dữ liệu. Thuật toán phân cụm K-Means có nhiều công dụng để nhóm các tài liệu văn bản, hình ảnh, video và hơn thế nữa.

Dấu thời gian:

Thêm từ xếp chồng lên nhau