K-means算法

一、K-均值是最普及的聚类算法,它接受一个未标记的数据集,然后将数据聚类成不同的组。其方法为:
1、首先选择K个随机的点,称为聚类中心。
2、簇分配:对于数据集中的每一个数据,计算其距离K个中心点的距离,将其与距离最近的中心点关联起来,与同一个中心点关联的所有点聚成一类。
3、移动聚类中心:计算每一个组的平均值,移动该组所关联的中心点到平均值的位置。
4、重复步骤2、3直至中心点不再变化。
μ 1 \mu ^{1} μ1, μ 2 \mu ^{2} μ2,…, μ k \mu ^{k} μk表示聚类中心,用 c ( 1 ) c^{\left ( 1 \right )} c(1), c ( 2 ) c^{\left ( 2 \right )} c(2),…, c ( m ) c^{\left ( m \right )} c(m)存储与第i个实例最近的聚类中心的索引,K-均值算法的伪代码如下:
在这里插入图片描述
K-均值最小化问题,是要最小化所有的数据点与其所关联的聚类中心点之间的距离之和。因此代价函数(畸变函数)为: J ( c ( 1 ) , . . . , c ( m ) , μ 1 , . . . , μ k ) = 1 m ∑ i = 1 m ∥ X ( i ) − μ c ( i ) ∥ 2 J\left ( c^{\left ( 1 \right )},...,c^{\left ( m \right )},\mu _{1},...,\mu _{k} \right )=\frac{1}{m}\sum_{i=1}^{m}\left \| X^{\left ( i \right )} -\mu _{c^{\left ( i \right )}}\right \|^{2} J(c(1),...,c(m),μ1,...,μk)=m1i=1mX(i)μc(i)2其中 μ c ( i ) \mu _{c^{\left ( i \right )}} μc(i)表示样本 x ( i ) x^{\left ( i \right )} x(i)所属簇的中心。
运行算法之前随机初始化聚类中心点的法则:
1、K<m,即聚类中心点的个数要小于所有训练集实例的数量;
2、随机选择K个训练实例,作为一开始的K个聚类中心。
K-均值存在一个问题是,它可能会停留在一个局部最小值处,而这取决于初始化的情况。为了解决这个问题,采用多次随机初始化的方法,每次都重新进行随机初始化,最后比较多次运行K-均值的结果,选择代价函数最小的结果。这种方法在K较小时(2–10)是可行的,但如果K较大,可能也不会明显地改善。
聚类数K通常需要根据不同的问题,人工进行选择。有一个可能用上的方法是“肘部法则”:改变聚类数K,然后进行聚类,计算损失函数,拐点处即为推荐的聚类数。
在这里插入图片描述
当损失函数随着K的增大平缓下降,拐点不明显时,肘部法则就不是一个选择K值的有效方法了。
二、以吴恩达机器学习课程练习材料实现,使用k-means聚类算法进行图像压缩,减少图像中出现的颜色数量,只剩下那些在图像中最常见的颜色。代码实现来源参考:吴恩达机器学习作业Python实现(七):K-means和PCA主成分分析
K-means算法实现相关函数代码如下:

from scipy.io import loadmat
import numpy as np
import matplotlib.pyplot as plt
from skimage import io

#找到离样本最近的簇中心点
def findClosestCentroids(X, centroids):
    idx = []    #存储最近的簇中心点对应的索引
    max_dist = 1000000  #限制最大距离
    for i in range(len(X)):
        dist = np.sum(np.square(X[i,:]-centroids), axis=1) #计算样本与每个簇中心点的距离
        if dist.min() < max_dist:
            ci = np.argmin(dist)    #获得距离最近的簇中心点的索引
            idx.append(ci)
    return np.array(idx)

#重新分配簇中心点
def computeCentroids(X, idx):
    centroids = []  #存储新的簇中心点
    for i in range(len(np.unique(idx))):    #以簇中心点数量进行循环
        u_k = X[idx == i].mean(axis=0)  #同一簇中心点下的样本按列求均值,得到新的簇中心点
        centroids.append(u_k)
    return np.array(centroids)

#实现K-means算法
def runKmeans(X, centroids, max_iters): 
    centroids_all = []  #存储每次簇中心点记录
    centroids_all.append(centroids)
    centroids_i = centroids
    for i in range(max_iters):
        idx = findClosestCentroids(X, centroids_i)  #找到离样本最近的簇中心点
        centroids_i = computeCentroids(X, idx)  #重新分配簇中心点
        centroids_all.append(centroids_i)
    return idx, centroids_all   #返回最后的分类结果及簇中心点记录

#从训练集中选择随机的样本进行簇中心点初始化
def initCentroids(X, K):
    m = X.shape[0]  #获得样本行数
    idx = np.random.choice(m, K)    
    centroids = X[idx]  #根据簇中心点数量随机抽取样本初始化
    return centroids

处理图像及聚类压缩的代码如下:

A = io.imread('bird_small.png')  #读取图片存储为ndarray对象
#print(A.shape)
A = A / 255 #设置像素值在0-1之间
X = A.reshape(-1, 3)    #ndarray调整为3列
K = 16
centroids = initCentroids(X, K) #随机初始化簇中心点
idx, centroids_all = runKmeans(X, centroids, 10)    #运行K-means算法
img = np.zeros(X.shape)
centroids = centroids_all[-1]   #获得最终的簇中心点
for i in range(len(centroids)):
    img[idx == i] = centroids[i]    #获得压缩后16个簇中心点表示的图像
img = img.reshape((128, 128, 3))    #调整为原来的图像格式
fig, axes = plt.subplots(1, 2, figsize=(12, 6)) #初始化图像为1行2列
axes[0].imshow(A)   #显示原来图像和压缩后的图像
axes[1].imshow(img)

将图片压缩为用16种颜色表示,原图像和压缩后的图像分别如下所示:
在这里插入图片描述

(结语个人日记:前几天回到了学校,办理完了毕业手续。面对离别,有说不出的感觉,也不太喜欢回忆四年的时光,因为回忆总让自己产生感慨情绪。当时间突然空闲下来,发现自己竟然不习惯了,那就珍惜当下,提升充实自己,为未来做好准备叭。)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值