Thực hiện thuật toán phân cụm k-means bằng tay

Một、Python triển khai k-means

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Để giảm số lần lặp, chúng ta nên khởi tạo tâm cụm trong phạm vi phân bố dữ liệu
def initialize_centroids(data, k):  # Định nghĩa hàm chọn ngẫu nhiên tâm cụm
    data_min = data.min() # Trả về giá trị nhỏ nhất của mỗi đặc trưng
    data_max = data.max() # Trả về giá trị lớn nhất của mỗi đặc trưng
    centroids = np.random.uniform(data_min, data_max, (k, data.shape[1])) # Tạo ngẫu nhiên K tâm cụm giữa giá trị lớn nhất và nhỏ nhất
    return centroids 

# Đóng gói thành hàm, tính khoảng cách từ một mẫu đến tất cả các tâm cụm và trả về khoảng cách nhỏ nhất cùng chỉ số tương ứng
def calculate_min_distance(sample, centroids):
    distances = np.sum(np.power((sample - centroids), 2), axis=1)  # Khoảng cách từ một mẫu đến tất cả các tâm cụm
    min_distance = distances.min() # Giá trị khoảng cách nhỏ nhất
    min_index = np.where(distances == min_distance)[0] # Chỉ số của khoảng cách ngắn nhất
    return min_distance, min_index



def kmeans_clustering(data, k):
    m, n = data.shape # Lấy số hàng và cột của tập dữ liệu
    centroids = initialize_centroids(data, k)
    
    # Thêm 3 cột bổ sung để lưu trữ thông tin khoảng cách và chỉ số cụm
    data_with_extra = np.zeros((m, 3))
    data_with_extra[:, 0] = np.inf
    data_with_extra[:, 1: 3] = -1
    data_extended = pd.concat([data, pd.DataFrame(data_with_extra)], axis=1)
    
    cluster_changed = True # Đặt biến điều khiển vòng lặp
    while cluster_changed: 
        cluster_changed = False # Đặt lại biến để tránh vòng lặp vô hạn
        for i in range(m): # Lặp qua từng mẫu trong tập dữ liệu
            min_dist, min_idx = calculate_min_distance(data_extended.iloc[i, :n].values, centroids) # Tính khoảng cách từ mẫu hiện tại đến k tâm cụm
            data_extended.iloc[i, n] = min_dist # Lưu khoảng cách nhỏ nhất vào cột thứ n
            # Lưu chỉ số cụm vào cột thứ n+1
            data_extended.iloc[i, n+1] = min_idx[0] 
        # Kiểm tra xem cột cuối cùng có thay đổi không, nếu có thì tiếp tục vòng lặp
        cluster_changed = not (data_extended.iloc[:, -1] == data_extended.iloc[:, -2]).all()
        # Tính toán lại tâm cụm
        if cluster_changed:
            new_centroids = data_extended.groupby(n+1).mean() # Tính trung bình cho mỗi cụm
            centroids = new_centroids.iloc[:, :n].values  # Gán giá trị trung bình làm tâm cụm mới
            data_extended.iloc[:, -1] = data_extended.iloc[:, -2] # Cập nhật chỉ số cụm hiện tại
            
    
    return centroids, data_extended

Hiệu quả như sau:

from sklearn.datasets import make_blobs # Nhập gói tạo tập dữ liệu

# Tạo tập dữ liệu mẫu
X, y = make_blobs(n_samples=500, n_features=2, centers=4, random_state=1)

plt.scatter(X[:, 0], X[:, 1]
            , marker='o' # Hình dạng điểm
            , s=8 # Kích thước điểm
           );

Biểu đồ phân bố tập dữ liệu:

Gọi thuật toán k-means tự viết để phân cụm:

centroids, clustered_data = kmeans_clustering(pd.DataFrame(X), 4)

plt.scatter(clustered_data.iloc[:, 0], clustered_data.iloc[:, 1], c=clustered_data.iloc[:, -1])
plt.scatter(centroids[:, 0], centroids[:, 1], c='r');

Kết quả vẫn rất tốt

Thẻ: k-means phân cụm thuật toán machine-learning python

Đăng vào ngày 19 tháng 5 lúc 15:33