手撕机器学习算法 | 聚类算法 | Kmeans

❗写在前面 ❗:

… … … … … … … … . … … …
1️⃣ 提供两种语言实现:本文提供两种语言实现,分别为Python和C++,分别依赖的核心库为Numpy和Eigen.

2️⃣ 提供关键步的公式推导:写出详尽的公式推导太花时间,所以只提供了关键步骤的公式推导。更详尽的推导,可移步其他博文或相关书籍.

3️⃣ 重在逻辑实现:文中的代码主要以实现算法的逻辑为主,在细节优化上面,并没有做更多的考虑,如果发现有不完善的地方,欢迎指出.


🌞 欢迎关注专栏,相应的内容会持续更新,祝大家变得更强!!
… … … … … … … … . … … …

1、原理推导


聚类分析(cluster analysis)是一类经典的无监督学习算法。在给定样本的情况下,聚类分析通过度量特征相似度或者距离,将样本自动划分为若干类别。

Kmeans是基于距离聚类中具有代表性的聚类算法。它的原理非常简单:

Kmeans聚类过程
  (1)初始化簇中心。在刚开始迭代的时候,随机选择k个样本作为初始化的簇中心。

  (2)按照样本与每个簇中心的距离进行聚类。将样本划分到与之距离最近的簇中。

  (3)根据划分的结果,计算新的簇中心。对每簇中的样本取均值,当作下一次迭代的簇中心。

  (4)如果迭代收敛或者满足迭代停止的条件,保存最终的簇中心结果


在进行预测的时候只需要判断当前样本与保存的簇中心距离,取最近的距离为其所属类别即可。

这里补充一些距离以及相似度的计算方法(仅Python实现):

import numpy as np

class SimilarityMeasure:

    # 欧氏距离
    def euclidean_distance(self, x1, x2):
        return np.sqrt(np.sum((x1 - x2) ** 2))

    # 曼哈顿距离
    def manhattan_distance(self, x1, x2):
        return np.sum(np.abs(x1 - x2))

    # 余弦相似
    def angle_cosine(self, x1, x2):
        dot_product = np.dot(x1, x2)
        norm_x1 = np.linalg.norm(x1)
        norm_x2 = np.linalg.norm(x2)
        return dot_product / (norm_x1 * norm_x2)

    # 相关性系数
    def correlation_coefficient(self, x1, x2):
        return np.corrcoef(x1, x2)[0, 1]

    # 马哈拉诺比斯距离
    def mahalanobis_distance(self, x1, x2):
        try:
            cov_inv = np.linalg.inv(np.cov(x1, x2))
            diff = x1 - x2
            return np.sqrt(np.dot(np.dot(diff, cov_inv), diff.T))
        except np.linalg.LinAlgError:
            return None

    # 切比雪夫距离
    def chebyshev_distance(self, x1, x2):
        return np.max(np.abs(x1 - x2))

2、算法实现

🌈Python实现

import numpy as np

class Kmeans:

    def __init__(self, k=2, max_iter=1000, distance_func=SimilarityMeasure().euclidean_distance):
        """
        :param k: 聚类的簇数
        :param max_iter: 最大迭代次数
        :param distance_func: 距离的计算方式,默认为欧氏距离
        """
        self.k = k
        self.max_iter = max_iter
        self.cluster_centers = None   # 簇中心
        self.calc_distance = distance_func  

    def fit(self, X):

        m, n = X.shape

        # 初始化随机的簇中心
        init_cluster_indices = np.random.choice(m, self.k, replace=False)
        init_cluster_centers = X[init_cluster_indices]

        for _ in range(self.max_iter):

            # 分配样本到最近的簇
            clusters = [[] for _ in range(self.k)]

            for x1 in X:
                min_distance = np.inf
                cluster_idx = None
                for i, x2 in enumerate(init_cluster_centers):
                    distance = self.calc_distance(x1, x2)

                    if distance < min_distance:
                        min_distance = distance
                        cluster_idx = i
                clusters[cluster_idx].append(x1)

            # 保存当前簇中心
            cur_cluster_centers = np.array(init_cluster_centers)

            # 计算新的簇中心
            init_cluster_centers = [np.mean(cluster, axis=0) for cluster in clusters]

            # 检查收敛性
            if np.linalg.norm(np.array(init_cluster_centers) - cur_cluster_centers) == 0:
                self.cluster_centers = np.array(init_cluster_centers)
                break

        self.cluster_centers = np.array(init_cluster_centers)

    def predict(self, X):

        y_pred = []
        for x1 in X:
            min_distance = np.inf
            cluster_idx = None
            for i, x2 in enumerate(self.cluster_centers):
                distance = self.calc_distance(x1, x2)

                if distance < min_distance:
                    min_distance = distance
                    cluster_idx = i
            y_pred.append(cluster_idx)
        return y_pred
# 演示
np.random.seed(42)
X = np.random.rand(20, 2)
kmeans = Kmeans(k=3, max_iter=100, distance_func=SimilarityMeasure().euclidean_distance)
kmeans.fit(X)
y_pred = kmeans.predict(X)

print("簇中心:\n", kmeans.cluster_centers)
print("预测的簇:\n", y_pred)

结果

簇中心:
 [[0.44564467 0.18482996]
 [0.12956495 0.93392146]
 [0.56328    0.62563539]]
预测的簇:
 [1, 2, 0, 1, 2, 1, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 1, 2, 0, 2]

⚡C++实现

  
 太简单了…略…有人需要再加…

3、总结

k均值聚类算法是众多聚类算法中最常用的代表性算法。作为一种动态迭代的算法,k均值聚类算法的主要步骤包括质心初始化、根据距离度量进行初步聚类、根据聚类结果计算新的质心、不断迭代聚类直至满足停止条件。这种不断动态迭代优化的算法,从思想上看有点像EM算法

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值