k-means

作者: dingtom | 来源:发表于2020-04-20 19:24 被阅读0次

    原理

    1. 随机从数据集中选择k个点作为我们聚类的中心点;
    2. 每个点分配到离它最近的类中心点,就形成了k类。然后重新计算每个类的中心点(比如取各类的均值作为新的中心点)
    3. 重复第2步,直到类不再发生变化,或者设置最大迭代次数,让算法收敛。

    练习

    2018 年世界杯中,很多球队没有进入到决赛圈,所以只有进入到决赛圈的球队才有实际的排名。如果是亚洲区预选赛 12 强的球队,排名会设置为 40。如果没有进入亚洲区预选赛 12 强,球队排名会设置为 50。



    首先,针对上面的排名,我们需要做的就是数据规范化,你可以把这些值划分到[0,1]或者按照均值为 0,方差为 1 的正态分布进行规范化。我先把数值规范化到了[0,1]空间中,得到了下面的数值表:



    我们随机选取中国、日本、韩国为三个类的中心点,我们就需要看下这些球队到中心点的距离。这里采用欧式距离。

    然后我们再重新计算这三个类的中心点,如何计算呢?最简单的方式就是取平均值,然后根据新的中心点按照距离远近重新分配球队的分类,再根据球队的分类更新中心点的位置。


    总结

    如何区分k-means与knn:

    • 都需要计算样本之间的距离
    • k-means是聚类算法,knn是有监督的分类算法;聚类没有标签,分类有标签
    • k-means中的k是k类,knn中的k是k个最近的邻居。

    k-means优点:

    • 原理比较简单,实现也是很容易,收敛速度快。
    • 聚类效果较优。
    • 算法的可解释度比较强

    k-means缺点:

    • K值的选取不好把握,一般根据经验或者已经有预判,其次是根据暴力试错k值选择最合适的分类数k。
    • 初始值的选取会影响最终聚类效果
    • 采用迭代方法,得到的结果只是局部最优。,并且目标函数SSE可能会达到局部最优解。这个有相应的改进方法,包括k-means++和二分k-means。
    • 非凸的数据集比较难收敛
    • 各隐含类别的数据不平衡效果不佳
    • 对噪声和异常点比较敏感

    sklearn

    KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')

    • n_clusters: 即 K 值,一般需要多试一些 K 值来保证更好的聚类效果。
    • max_iter:最大迭代次数
    • n_init:初始化中心点的运算次数,默认是 10。运行 n_init 次, 取其中最好的作为初始的中心点。如果 K 值比较大的时候,你可以适当增大 n_init 这个值;
    • init:即初始值选择的方式,默认k-means++ ,你也可以自己指定中心点
    • algorithm:k-means 的实现算法,有“auto” “full”“elkan”三种。如果你选择"full"采用的是传统的 K-Means 算法,“auto”会根据数据的特点自动选择是选择“full”还是“elkan”。

    返回值:

    • cluster_centers_,聚类中心的坐标。如果算法在完全收敛之前停止(见tol和max iter),这些将与标签不一致。
    • labels_,每个点的标记
    • inertia_,样本到其最近的簇中心的距离的平方和
    • n_iter迭代运行次数。
    #############K-means-鸢尾花聚类############
    import matplotlib.pyplot as plt
    import numpy as np
    from sklearn.cluster import KMeans
    #from sklearn import datasets
    from sklearn.datasets import load_iris
    iris = load_iris()
    X = iris.data
    y = iris.target
    
    #绘制数据分布图
    plt.scatter(X[:, 0], X[:, 1], c="red", marker='o', label='see')
    plt.xlabel('petal length')
    plt.ylabel('petal width')
    plt.legend()
    plt.show()
     
    estimator = KMeans(n_clusters=3)#构造聚类器
    estimator.fit(X)#聚类
    print(X.shape)  # (150, 4)
    label_pred = estimator.labels_  # 获取聚类标签
    print('聚类结果', '\n', label_pred)  # (150,) [1 1 1 1 1 2 2 2 2 2 0 2 2 2 2 0 2 2 ...]
    print('真实类别', '\n', y)
    
    x0 = X[label_pred == 0]
    x1 = X[label_pred == 1]
    x2 = X[label_pred == 2]
    print(x0.shape, x1.shape, x2.shape)  # (62, 4) (50, 4) (38, 4)
    plt.scatter(x0[:, 0], x0[:, 1], c="red", marker='o', label='label0')
    plt.scatter(x1[:, 0], x1[:, 1], c="green", marker='*', label='label1')
    plt.scatter(x2[:, 0], x2[:, 1], c="blue", marker='+', label='label2')
    plt.xlabel('petal length')
    plt.ylabel('petal width')
    plt.legend()
    plt.show()
    

    图像分割

    # -*- coding: utf-8 -*-
    # 使用K-means对图像进行聚类,并显示聚类压缩后的图像
    import numpy as np
    import PIL.Image as image
    from sklearn.cluster import KMeans
    from sklearn import preprocessing
    import matplotlib.image as mpimg
    # 加载图像,并对数据进行规范化
    def load_data(filePath):
        # 读文件
        f = open(filePath,'rb')
        data = []
        # 得到图像的像素值
        img = image.open(f)
        # 得到图像尺寸
        width, height = img.size
        for x in range(width):
            for y in range(height):
                # 得到点(x,y)的三个通道值
                c1, c2, c3 = img.getpixel((x, y))
                data.append([(c1+1)/256.0, (c2+1)/256.0, (c3+1)/256.0])
        f.close()
        return np.mat(data), width, height
    # 加载图像,得到规范化的结果imgData,以及图像尺寸
    img, width, height = load_data('./weixin.jpg')
    # 用K-Means对图像进行16聚类
    kmeans =KMeans(n_clusters=16)
    label = kmeans.fit_predict(img)
    # 将图像聚类结果,转化成图像尺寸的矩阵
    label = label.reshape([width, height])
    # 创建个新图像img,用来保存图像聚类压缩后的结果
    img=image.new('RGB', (width, height))
    for x in range(width):
        for y in range(height):
            c1 = kmeans.cluster_centers_[label[x, y], 0]
            c2 = kmeans.cluster_centers_[label[x, y], 1]
            c3 = kmeans.cluster_centers_[label[x, y], 2]
            img.putpixel((x, y), (int(c1*256)-1, int(c2*256)-1, int(c3*256)-1))
    img.save('weixin_new.jpg')
    

    相关文章

      网友评论

          本文标题:k-means

          本文链接:https://www.haomeiwen.com/subject/ygmjihtx.html