MinibatchKmeans——牺牲精度换取效率的一种kmeans改良

申明:本代码为chatgpt生成,作者乃菜鸟一枚。 

大致算法流程:

  1. 随机选取k个质心
  2. 根据设定的batch_size大小随机选取batch_size个样本作为代表样本集
  3. 计算代表样本集中每个样本到每个质心的距离,分别归到最近的质心所在簇
  4. 计算当前聚类簇的平均值,作为新的质心(原质心也参与平均值的计算)
  5. 判断是否已经收敛:如果聚类标签不再改变,则结束迭代
  6. 重复执行2-5步,直到算法收敛

参数:参照sklean.Minibatchkmeans,此处参数为:

  1. X:数据集
  2. y_pred_init:标签
  3. n_cluster:簇数
  4. batch_size:代表样本集大小
  5. n_init:随机选取初始质心次数
  6. max_iter:最大迭代次数
# 运行 mini-batch kmeans 算法
minibatch_kmeans(X, y, n_clusters=2, batch_size=5, n_init=1, max_iter=15)

样本集:生成了一个只有30个样本,二维的,分为两类的样本集

# 生成 30 个样本,每个样本有 2个特征,分为 2 类
X = np.concatenate([
    np.random.normal(loc=[0, 0], scale=[0.3, 0.3], size=(10, 2)),  # 类别 0
    np.random.normal(loc=[2, 2], scale=[0.3, 0.3], size=(10, 2)),  # 类别 1
])

 

运行效果展示:

1.初始质心,将所有样本标签初始化为-1,表示未分类

  

 2.随机选取batch(batch_size=5)

 

  3. 计算距离、更新标签

        显然样本4距离质心一更近,故被赋予标签‘0’

 4.更新质心

        下面这张更加明显 

 

 5.把batch中的聚类结果合并到整个数据集中



6.判断收敛 

            n_iter_tol = 2  # 连续多少轮聚类结果相同认为已经收敛
            # 判断聚类是否已经收敛
            if  np.array_equal(y_pred, y):
                n_iter_same += 1
                if n_iter_same >= n_iter_tol:
                    break
            else:
                n_iter_same = 0

每轮聚类结果:

 

   

  

    第九轮和第十轮两轮没变化,结束迭代。

 完整代码:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)#删掉该值,每次随机生成样本集
n_iter_tol = 2  # 连续多少轮聚类结果相同认为已经收敛
def minibatch_kmeans(X, y, n_clusters, batch_size, n_init, max_iter):
    for i in range(n_init):
        # 初始化聚类标签:将所有样本的标签初始化为 -1(表示未知)
        y = np.zeros(X.shape[0], dtype=int) - 1
        # 初始化聚类质心和上一轮迭代的聚类结果
        centroids = X[np.random.choice(X.shape[0], n_clusters, replace=False)]
        y_pred = np.zeros(X.shape[0], dtype=np.int32) - 1
    
        # 绘制初始化的聚类质心和所有样本点
        plt.scatter(X[:, 0], X[:, 1], c='gray', alpha=0.5)
        plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='black', s=100)
        plt.title("Initialization")
        plt.show()
    
        for j in range(max_iter):
            print('第', j+ 1, '轮:y_pred=', y_pred)
            print('质心:', centroids)
            # 随机选择一个 mini-batch
            batch_indices = np.random.choice(X.shape[0], batch_size, replace=False)
            X_batch = X[batch_indices]
            y_pred_batch = y[batch_indices]
            print('batch_indices:', batch_indices)
            print('选的小样本集', X_batch)
            print('小样本集的标签', y_pred_batch)
    
            # 绘制 mini-batch 中的样本点和聚类质心
            plt.scatter(X[:, 0], X[:, 1], c='gray', alpha=0.5)
            plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='black', s=100)
            plt.scatter(X_batch[:, 0], X_batch[:, 1], c='blue', alpha=0.5)
            plt.title("Iteration %d: Selected mini-batch" % (j+1))
            plt.show()
    
            # 计算每个样本到每个质心的距离
            distances = np.sqrt(((X_batch - centroids[:, np.newaxis])**2).sum(axis=2))
            print('每个质心到每个样本的距离:', distances)
    
            # 将每个样本分配到距离最近的质心所在的聚类
            y_pred_batch = np.argmin(distances, axis=0)
            print('新y_pred_batch:', y_pred_batch)
    
            for k in range(n_clusters):
                # 选出当前聚类簇所属的样本点(包括原来的质心)
                cluster_points = np.vstack((X_batch[y_pred_batch == k], centroids[k]))
                # 计算当前聚类簇的平均值,作为新的质心
                if len(cluster_points) > 0:
                    centroids[k] = np.mean(cluster_points, axis=0)
    
            # 绘制更新后的聚类质心和未知样本点
            plt.scatter(X[:, 0], X[:, 1], c='gray', alpha=0.5)
            plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='black', s=100)
            plt.title("Iteration %d: Update centroids" % (j+1))
            plt.show()
    
            # 将 mini-batch 中的聚类结果合并到整个数据集中
            y[batch_indices] = y_pred_batch
            print('y:',y)
    
            # 绘制 mini-batch 中的聚类结果和未知样本点
            plt.scatter(X[:, 0], X[:, 1], c=y, cmap='rainbow', alpha=0.5)
            plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='black', s=100)
            plt.title("Iteration %d: Mini-batch clustering" % (j+1))
            plt.show()


            print('y_pred:',y_pred)
            # 判断聚类是否已经收敛
            if  np.array_equal(y_pred, y):
                n_iter_same += 1
                if n_iter_same >= n_iter_tol:
                    break
            else:
                n_iter_same = 0

            y_pred = y.copy()
    
    
        # 绘制每个样本归为最近质心所在簇后的聚类结果和未知样本点
        distances = np.sqrt(((X - centroids[:, np.newaxis])**2).sum(axis=2))
        y_pred_final = np.argmin(distances, axis=0)
        plt.scatter(X[:, 0], X[:, 1], c=y_pred_final, cmap='rainbow', alpha=0.5)
        plt.scatter(centroids[:, 0], centroids[:, 1], marker='x', color='black', s=100)
        plt.title("Final clustering")
        plt.show()


# 生成 30 个样本,每个样本有 2个特征,分为 2 类
X = np.concatenate([
    np.random.normal(loc=[0, 0], scale=[0.3, 0.3], size=(10, 2)),  # 类别 0
    np.random.normal(loc=[2, 2], scale=[0.3, 0.3], size=(10, 2)),  # 类别 1
])
# 初始化聚类标签:将所有样本的标签初始化为 -1(表示未知)
y = np.zeros(X.shape[0], dtype=int) - 1
# 运行 mini-batch kmeans 算法
minibatch_kmeans(X, y, n_clusters=2, batch_size=5, n_init=1, max_iter=15)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值