k-means聚类算法的python实现和sklearn的聚类器

k-means聚类算法的python实现和sklearn的聚类器

1. 标准k-means聚类算法

k-means是一个迭代算法,需要人为指定聚类数量。因为实现简单、对大样本有很好的拓展性被广泛采用。
算法初始化阶段首先随机选取不重复的 k k k个点作为 初始的聚类中心(称为Centroid)。不断重复执行以下两个步骤:

  • 给每个点 x i x_i xi分配所属类别 l i l_i li
    l i = a r g m i n j { d ( x i , μ j ) } l_i=\mathop{argmin}_{j}\{d(x_i,\mu_j)\} li=argminj{d(xi,μj)}
  • 根据分配结果重新计算每个聚类的均值
    μ j = 1 { l i = j } x i 1 { l i = j } \mu_j=\frac{1\{l_i=j \}x_i}{1\{l_i=j\}} μj=1{li=j}1{li=j}xi

实现代码如下,实际上实现k-means算法的代码只有def k_means(dist, xy, k,centroids=None):的几行。

# k-means 聚类算法

import numpy as np
import numpy.linalg as la
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
plt.rcParams.update({
    'savefig.dpi': 600,
    'mathtext.fontset':'cm',
    'font.sans-serif':'SimHei',
    'axes.unicode_minus': False
})

def k_means(dist, xy, k,centroids=None):
    # 随机不重复地选取 k 个点作为初始聚类中心
    if not centroids:
        centroids = np.random.choice(np.arange(dist.shape[0]),k,replace=False)
    index = np.arange(dist.shape[0])
    while True:
        # 给每个点分配所属类别
        groupid = np.argmin(dist[:,centroids], axis=-1)
        # 生成类别索引
        groups = [np.where(groupid == id,True,False) for id in range(len(centroids))]
        # 重新计算每一类的均值
        kmeans = np.array([np.mean(xy[group],axis=0) for group in groups])
        # 重新选定聚类中心
        centroids_new = np.argmin(la.norm(xy[:,None,:] - kmeans,ord=2,axis=-1)**2,axis=0)
        # 如果聚类中心不再变化,算法结束
        if np.all(centroids == centroids_new):
            return centroids,[index[group] for group in groups]
        centroids = centroids_new
        
def get_dist():
    X,Y = np.meshgrid(np.arange(10),np.arange(10))
    xy = np.vstack((X.ravel(),Y.ravel())).T
    dist = la.norm(xy[:,None,:] - xy,ord=2, axis=-1)
    
    return dist, np.array(xy)
_, xy = get_dist()
X,Y = xy[:,0],xy[:,1]
fig,ax = plt.subplots()
ax.scatter(X.ravel(),Y.ravel(),marker='o',facecolor='white',edgecolor='k')
plt.show()
    
def cluster_diagram(centroids, groups, cmap=['r','g','b','k'],centroids_marker='D'):
    # 'D' -- 'diamond'
    fig, ax = plt.subplots()
    for i in range(len(centroids)):
        group,center = groups[i],centroids[i]
        ax.scatter(X[group],Y[group],marker='o',facecolor='white',edgecolor=cmap[i])
        ax.scatter(X[center],Y[center],marker=centroids_marker,facecolor='white',edgecolor=cmap[i],linewidth=2)
    plt.show()
    

def main():
    dist, xy = get_dist()
    centroids, groups = k_means(dist,xy,4)
#     centroids, groups = k_means(*get_dist(),4,centroids=[54,55,64,65])
    print(centroids, *groups,sep='\n')
    cluster_diagram(centroids,groups)
    
    # sklearn.cluster.KMeans 
    kmeans = KMeans(4)
    kmeans.fit(xy)
    print(kmeans.labels_,kmeans.cluster_centers_,sep='\n')

if __name__ == '__main__':
    main()

首先生成了坐标系上的 100 100 100个点坐标和相应的距离矩阵。这里是点的坐标分布:
在这里插入图片描述

经过k_means函数聚类后画出聚类结果图。这里是聚类结果:(选取最中间的四个点[54,55,64,65]可以得到最均匀的聚类结果)
在这里插入图片描述

最后调用了sklearn.cluster.KMeans,和它的结果对比。

我的函数k_means():
聚类中心:[22 27 72 77]
所属类别:
[ 0  1  2  3  4 10 11 12 13 14 20 21 22 23 24 30 31 32 33 34 40 41 42 43
 44]
[ 5  6  7  8  9 15 16 17 18 19 25 26 27 28 29 35 36 37 38 39 45 46 47 48
 49]
[50 51 52 53 54 60 61 62 63 64 70 71 72 73 74 80 81 82 83 84 90 91 92 93
 94]
[55 56 57 58 59 65 66 67 68 69 75 76 77 78 79 85 86 87 88 89 95 96 97 98
 99]

skleaern.cluster.KMeans:
聚类中心:
[[2. 2.]
 [2. 7.]
 [7. 7.]
 [7. 2.]]
 所属类别:
 [0 0 0 0 0 3 3 3 3 3 0 0 0 0 0 3 3 3 3 3 0 0 0 0 0 3 3 3 3 3 0 0 0 0 0 3 3
 3 3 3 0 0 0 0 0 3 3 3 3 3 1 1 1 1 1 2 2 2 2 2 1 1 1 1 1 2 2 2 2 2 1 1 1 1
 1 2 2 2 2 2 1 1 1 1 1 2 2 2 2 2 1 1 1 1 1 2 2 2 2 2]

2. sklearn.cluster.KMeans

第一节的代码用到了sklearn.cluster.KMeans,这里搬运一个官方文档给出的示例代码:

>>> from sklearn.cluster import KMeans
>>> import numpy as np
>>> X = np.array([[1, 2], [1, 4], [1, 0],
...               [10, 2], [10, 4], [10, 0]])
>>> kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
>>> kmeans.labels_
# 给出每个点所属类别的向量
array([1, 1, 1, 0, 0, 0], dtype=int32)
>>> kmeans.predict([[0, 0], [12, 3]])
# 预测类别
array([1, 0], dtype=int32)
>>> kmeans.cluster_centers_
# 聚类中心
array([[10.,  2.],
       [ 1.,  2.]])
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值