K-Means++代码实现

K-Means++代码实现

数据集
https://download.csdn.net/download/qq_43629083/87246495

import pandas as pd
import numpy as np
import random
import math
%matplotlib inline
from matplotlib import pyplot as plt

# 按文件名读取整个文件
data = pd.read_csv('data.csv')
class MyKmeansPlusPlus:
    def __init__(self, k, max_iter = 10):
        self.k = k
        # 最大迭代次数
        self.max_iter = max_iter
        # 训练集
        self.data_set = None
        # 结果集
        self.labels = None
    
    '''
    计算两点间的欧拉距离
    '''
    def euler_distance(self, point1, point2):
        distance = 0.0
        for a, b in zip(point1, point2):
            distance += math.pow(a - b, 2)
        return math.sqrt(distance)
    
    '''
    计算样本中的每一个样本点与已经初始化的聚类中心之间的距离,并选择其中最短的距离
    '''
    def nearest_distance(self, point, cluster_centers):
        min_distance = math.inf
        dim = np.shape(cluster_centers)[0]
        for i in range(dim):
            # 计算point与每个聚类中心的距离
            distance = self.euler_distance(point, cluster_centers[i])
            # 选择最短距离
            if distance < min_distance:
                min_distance = distance
        return min_distance
    
    '''
    初始化k个聚类中心
    '''
    def get_centers(self):
        dim_m, dim_n = np.shape(self.data_set)
        cluster_centers = np.array(np.zeros(shape = (self.k, dim_n)))
        #随机初始化第一个聚类中心点
        index = np.random.randint(0, dim_m)
        cluster_centers[0] = self.data_set[index]
        
        # 初始化一个距离序列
        distances = [0.0 for _ in range(dim_m)]
        
        for i in range(1, self.k):
            print("i = ", i)
            sum_all = 0.0
            for j in range(dim_m):
                # 对每一个样本找到最近的聚类中心点
                distances[j] = self.nearest_distance(self.data_set[j], cluster_centers[0:i])
                # 将所有最短距离相加
                sum_all += distances[j]
            # 取得sum_all之间的随机值
            sum_all *= random.random()
            # 以概率获得距离最远的样本点作为聚类中心
            for id, dist in enumerate(distances):
                sum_all -= dist
                if sum_all > 0:
                    continue
                cluster_centers[i] = self.data_set[id]
                break;
        return cluster_centers
    
    '''
    确定非中心点与哪个中心点最近
    '''
    def get_closest_index(self, point, centers):
        # 初始值设为最大
        min_dist = math.inf
        label = -1
        # enumerate() 函数同时列出数据和数据下标
        for i, center in enumerate(centers):
            dist = self.euler_distance(center, point)
            if dist < min_dist:
                min_dist = dist
                label = i
        return label
    
    '''
    更新中心点
    '''
    def update_centers(self):
        # k类点分别存
        points_label = [[] for i in range(self.k)]
        for i, label in enumerate(self.labels):
            points_label[label].append(self.data_set[i])
        centers = []
        for i in range(self.k):
            centers.append(np.mean(points_label[i], axis = 0))
        return centers
    
    '''
    判断是否停止迭代,新中心点与旧中心点一致或者达到设置的迭代最大值则停止
    '''
    def stop_iter(self, old_centers, centers, step):
        if step > self.max_iter:
            return True
        return np.array_equal(old_centers, centers)
    
    '''
    模型训练
    '''
    def fit(self, data_set):
        self.data_set = data_set.drop(['labels'], axis = 1)
        self.data_set = np.array(self.data_set)
        point_num = np.shape(data_set)[0]
        # 初始化结果集
        self.labels = data_set.loc[:, 'labels']
        self.labels = np.array(self.labels)
        
        # 初始化k个聚类中心点
        centers = self.get_centers()
        
        # 保存上一次迭代的中心点
        old_centers = []
        # 当前迭代次数
        step = 0
        flag = False
        while not flag:
            # 存储 旧的中心点
            old_centers = np.copy(centers)
            # 迭代次数+1
            step += 1
            print("current iteration: ", step)
            print("current centers: ", old_centers)
            # 本次迭代 各个点所属类别(即该点与哪个中心点最近)
            for i, point in enumerate(self.data_set):
                self.labels[i] = self.get_closest_index(point, centers)
            # 更新中心点
            centers = self.update_centers()
            # 迭代是否停止的标志
            flag = self.stop_iter(old_centers, centers, step)
            centers = np.array(centers)
            fig = plt.figure()
            label0 = plt.scatter(self.data_set[:, 0][self.labels == 0], self.data_set[:, 1][self.labels == 0])
            label1 = plt.scatter(self.data_set[:, 0][self.labels == 1], self.data_set[:, 1][self.labels == 1])
            label2 = plt.scatter(self.data_set[:, 0][self.labels == 2], self.data_set[:, 1][self.labels == 2])
            plt.scatter(old_centers[:, 0], old_centers[:, 1], marker='^', edgecolor='black', s=128)

            plt.title('labeled data')
            plt.xlabel('V1')
            plt.ylabel('V2')
            plt.legend((label0, label1, label2), ('label0', 'label1', 'label2'))
            plt.show()
myKmeansPP = MyKmeansPlusPlus(3)
myKmeansPP.fit(data)

current iteration: 1
current centers:
[[55.97659 75.71833 ]
[43.75808 67.45812 ]
[71.72321 -7.872746]]

请添加图片描述

current iteration: 2
current centers:
[[55.83404759 70.21560931]
[30.35261288 47.71518861]
[50.15798861 -5.34769581]]

请添加图片描述

current iteration: 3
current centers:
[[47.66230967 65.1238036 ]
[22.93488 39.05383154]
[52.52023009 -6.18734425]]

请添加图片描述

current iteration: 4
current centers:
[[42.96329079 61.70702396]
[12.28521822 20.36196405]
[63.73622886 -9.02914858]]

请添加图片描述

current iteration: 5
current centers:
[[ 40.8388755 59.95703427]
[ 9.62033389 11.15366963]
[ 69.77599323 -10.09654797]]

请添加图片描述

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
k-means++是一种改进的k-means聚类算法,它通过选择初始聚类中心的方式来提高聚类结果的质量。而肘部法则(Elbow Method)是一种常用的确定聚类数目的方法。下面是使用Matlab实现k-means++和肘部法则的代码示例: ```matlab % 生成示例数据 data = rand(100, 2); % 设置聚类数目的范围 k_range = 1:10; % 存储每个k值对应的聚类误差平方和 sse = zeros(length(k_range), 1); % 使用k-means++算法和肘部法则确定最佳聚类数目 for k = k_range % 使用k-means++算法进行聚类 [idx, centers, sumd] = kmeans(data, k, 'Start', 'plus'); % 计算聚类误差平方和 sse(k) = sum(sumd); end % 绘制肘部法则图像 figure; plot(k_range, sse, 'o-'); xlabel('Number of Clusters (k)'); ylabel('Sum of Squared Errors (SSE)'); title('Elbow Method'); % 根据肘部法则选择最佳聚类数目 best_k = input('Please select the best number of clusters based on the elbow method: '); % 使用最佳聚类数目进行最终聚类 [idx, centers] = kmeans(data, best_k, 'Start', 'plus'); % 绘制聚类结果 figure; gscatter(data(:,1), data(:,2), idx); hold on; plot(centers(:,1), centers(:,2), 'kx', 'MarkerSize', 10, 'LineWidth', 2); xlabel('Feature 1'); ylabel('Feature 2'); title('K-means Clustering'); ``` 在上述代码中,首先生成了一个示例数据集`data`,然后通过循环尝试不同的聚类数目`k`,使用`kmeans`函数进行k-means++聚类,并计算聚类误差平方和。接着,绘制了肘部法则图像,用户需要根据图像选择最佳聚类数目`best_k`。最后,使用最佳聚类数目进行最终聚类,并绘制聚类结果。 希望以上代码能够帮助到你!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

树下一朵云

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值