Python手撕kmeans源码

参考了两篇文章

K-Means及K-Means++算法Python源码实现-CSDN博客

使用K-means算法进行聚类分析_kmeans聚类分析结果怎么看-CSDN博客

# 定义kmeans类
from copy import deepcopy
from sklearn.datasets import make_blobs
import numpy as np
import matplotlib.pyplot as plt

class kMeans():
    def __init__(self, input_data, k=3, max_epnoch=100):
        """
        :param input_data: 一个numpy数组 为样本特征数值型数据集
        :param k: 分成几组,整数
        :max_epnoch: 最大迭代次数
        """
        self.data = input_data
        self.k = k
        self.max_epnoch = max_epnoch
        self.capacity = len(input_data)
        self.centers = []  # 用于保存族的质心
        self.clusters = np.zeros(self.capacity)  # 用于保存数据所属的族

    def get_init_clustcen(self):
        # 随机初始化聚类中心
        #     k值合理性检验
        if self.k < 1 or self.k > self.capacity:
            raise Exception('k值输入错误')
        # 打乱样本 取前k个
        indexs = np.arange(self.capacity)
        np.random.shuffle(indexs)
        # indexs[:self.k] 取前k个index
        # 这样就随机取k个样本作为组质心
        self.centers = self.data[indexs[:self.k],:]     # data[nums,:]注意这种切片方式必须要data是np数组才可以
        return

    def get_distance(self, data1, data2):
        # 计算同列的数据的欧式距离   diff相减时用到了广播机制
        diff = data1 - data2
        return np.sum(np.power(diff, 2), axis= 1)**0.5   # 按列进行求和

        # np.argmax得到np数组中最小值的索引
    def cluster_pross(self):
        # 用来保存聚类中心的旧值,一开始初始化为0
        old_center = np.zeros(self.centers.shape)
        # 迭代标识符,记录新旧聚类中心的距离
        distance_flag = self.get_distance(old_center, self.centers)

        # 若聚类中心不再变化或者达到迭代次数 则退出 否则才执行循环
        while np.sum(distance_flag) != 0 and self.max_epnoch:
            # 1. 计算每个样本点所属的族
            for i in range(self.capacity):
                # 样本与各族的距离(样本与各族的列是相同的 因此可调用前面准备的函数)
                distance_i = self.get_distance(self.data[i], self.centers)
                # 获得当前样本点与族最近的那个族的索引
                cluster_i = np.argmin(distance_i)
                # 记录当前样本点所属的聚类中心
                self.clusters[i] = cluster_i

            # 2. 更新聚类中心
            # 记录之前的聚类中心
            old_center = deepcopy(self.centers)
            # 按照族来计算,将属于同一组的样本堆叠在一起 计算均值作为聚类中心
            for i in range(self.k):
                tmp = [self.data[j] for j in range(self.capacity) if self.clusters[j] == i]
                # 按列计算均值,并将其存储在新的聚类中心中
                self.centers[i] = np.mean(tmp, axis= 0)

            # 3. 更新迭代条件的值
            self.max_epnoch -= 1
            distance_flag = self.get_distance(old_center, self.centers)
            
        return self.centers, self.clusters
# 实例化并作图前后对比
# 获取数据集 并用图像呈现
X, _ = make_blobs(n_samples=150, n_features=2, centers=3, cluster_std=0.5, random_state=0)
plt.scatter(X[:,0], X[:,1], c='r', marker='o') # 将white改为其他的颜色
plt.grid()
plt.show()

Python手撕kmeans源码_第1张图片

# 实例化一个聚类对象
kmeans_X = kMeans(X)
# 随机初始化聚类中心
kmeans_X.get_init_clustcen()
# 进行聚类 并接结果 为了作图 返回的是聚类中心数据 和 对应样本i的所属聚类
centers, clusters = kmeans_X.cluster_pross()        # 其中 centers(k,n_features)   cluters(n_samples, 1)


# 可视化聚类结果
plt.scatter(X[clusters == 0, 0], X[clusters == 0, 1], s=50, c='lightgreen', marker='s', label='cluster 1')
plt.scatter(X[clusters == 1, 0], X[clusters == 1, 1], s=50, c='orange', marker='o', label='cluster 2')
plt.scatter(X[clusters == 2, 0], X[clusters == 2, 1], s=50, c='lightblue', marker='v', label='cluster 3')
plt.scatter(centers[:,0], centers[:,1], s=250, c='red', marker='*', label='centroids')
plt.legend()
plt.grid()
plt.show()

Python手撕kmeans源码_第2张图片

Python手撕kmeans源码_第3张图片

你可能感兴趣的:(每天都要刷算法,kmeans,算法,机器学习)