前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数据挖掘算法—K-Means算法

数据挖掘算法—K-Means算法

作者头像
用户9925864
发布2022-07-27 08:43:35
3980
发布2022-07-27 08:43:35
举报
文章被收录于专栏:算法工程师的学习日志

一位读者建议多分享一些具体算法相关的内容,这期分享一下数据挖掘相关的算法。

简介

又叫K-均值算法,是非监督学习中的聚类算法。

基本思想

k-means算法比较简单。在k-means算法中,用cluster来表示簇;容易证明k-means算法收敛等同于所有质心不再发生变化。基本的k-means算法流程如下:

选取k个初始质心(作为初始cluster,每个初始cluster只包含一个点); repeat: 对每个样本点,计算得到距其最近的质心,将其类别标为该质心所对应的cluster; 重新计算k个cluster对应的质心(质心是cluster中样本点的均值); until 质心不再发生变化

repeat的次数决定了算法的迭代次数。实际上,k-means的本质是最小化目标函数,目标函数为每个点到其簇质心的距离的平方和:

N是元素个数,x表示元素,c(j)表示第j簇的质心

算法复杂度

时间复杂度是O(nkt) ,其中n代表元素个数,t代表算法迭代的次数,k代表簇的数目

优缺点

优点

简单、快速;

对大数据集有较高的效率并且是可伸缩性的;

时间复杂度近于线性,适合挖掘大规模数据集。

缺点

k-means是局部最优,因而对初始质心的选取敏感;

选择能达到目标函数最优的k值是非常困难的。

代码

代码语言:javascript
复制
# coding:utf-8

import numpy as np
import matplotlib.pyplot as plt


def loadDataSet(fileName):
    '''
    加载测试数据集,返回一个列表,列表的元素是一个坐标
    '''
    dataList = []
    with open(fileName) as fr:
        for line in fr.readlines():
            curLine = line.strip().split('\t')
            fltLine = list(map(float, curLine))
            dataList.append(fltLine)
    return dataList


def randCent(dataSet, k):
    '''
    随机生成k个初始的质心
    '''
    n = np.shape(dataSet)[1]  # n表示数据集的维度
    centroids = np.mat(np.zeros((k, n)))
    for j in range(n):
        minJ = min(dataSet[:, j])
        rangeJ = float(max(dataSet[:, j]) - minJ)
        centroids[:, j] = np.mat(minJ + rangeJ * np.random.rand(k, 1))
    return centroids


def kMeans(dataSet, k):
    '''
    KMeans算法,返回最终的质心坐标和每个点所在的簇
    '''
    m = np.shape(dataSet)[0]  # m表示数据集的长度(个数)
    clusterAssment = np.mat(np.zeros((m, 2)))

    centroids = randCent(dataSet, k)  # 保存k个初始质心的坐标
    clusterChanged = True
    iterIndex = 1  # 迭代次数
    while clusterChanged:
        clusterChanged = False
        for i in range(m):
            minDist = np.inf
            minIndex = -1
            for j in range(k):
                distJI = np.linalg.norm(np.array(centroids[j, :]) - np.array(dataSet[i, :]))
                if distJI < minDist:
                    minDist = distJI
                    minIndex = j
            if clusterAssment[i, 0] != minIndex: clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist ** 2
            print("第%d次迭代后%d个质心的坐标:\n%s" % (iterIndex, k, centroids))  # 第一次迭代的质心坐标就是初始的质心坐标
            iterIndex += 1
        for cent in range(k):
            ptsInClust = dataSet[np.nonzero(clusterAssment[:, 0].A == cent)[0]]  # get all the point in this cluster
            centroids[cent, :] = np.mean(ptsInClust, axis=0)
    return centroids, clusterAssment


def showCluster(dataSet, k, centroids, clusterAssment):
    '''
    数据可视化,只能画二维的图(若是三维的坐标图则直接返回1)
    '''
    numSamples, dim = dataSet.shape
    if dim != 2:
        return 1

    mark = ['or', 'ob', 'og', 'ok', 'oy', 'om', 'oc', '^r', '+r', 'sr', 'dr', '<r', 'pr']

    # draw all samples
    for i in range(numSamples):
        markIndex = int(clusterAssment[i, 0])
        plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])

    mark = ['Pr', 'Pb', 'Pg', 'Pk', 'Py', 'Pm', 'Pc', '^b', '+b', 'sb', 'db', '<b', 'pb']
    # draw the centroids
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=12)

    plt.show()


if __name__ == '__main__':
    dataMat = np.mat(loadDataSet('./data.txt'))  # mat是numpy中的函数,将列表转化成矩阵
    k = 6  # 选定k值,也就是簇的个数(可以指定为其他数)
    cent, clust = kMeans(dataMat, k)
    showCluster(dataMat, k, cent, clust)

txt内容为:

代码语言:javascript
复制
1.658985  4.285136
-3.453687  3.424321
4.838138  -1.151539
-5.379713  -3.362104
0.972564  2.924086
-3.567919  1.531611
0.450614  -3.302219
-3.487105  -1.724432
2.668759  1.594842
-3.156485  3.191137
3.165506  -3.999838
-2.786837  -3.099354
4.208187  2.984927
-2.123337  2.943366
0.704199  -0.479481
-0.392370  -3.963704
2.831667  1.574018
-0.790153  3.343144
2.943496  -3.357075
-3.195883  -2.283926
2.336445  2.875106
-1.786345  2.554248
2.190101  -1.906020
-3.403367  -2.778288
1.778124  3.880832
-1.688346  2.230267
2.592976  -2.054368
-4.007257  -3.207066
2.257734  3.387564
-2.679011  0.785119
0.939512  -4.023563
-3.674424  -2.261084
2.046259  2.735279
-3.189470  1.780269
4.372646  -0.822248
-2.579316  -3.497576
1.889034  5.190400
-0.798747  2.185588
2.836520  -2.658556
-3.837877  -3.253815
2.096701  3.886007
-2.709034  2.923887
3.367037  -3.184789
-2.121479  -4.232586
2.329546  3.179764
-3.284816  3.273099
3.091414  -3.815232
-3.762093  -2.432191
3.542056  2.778832
-1.736822  4.241041
2.127073  -2.983680
-4.323818  -3.938116
3.792121  5.135768
-4.786473  3.358547
2.624081  -3.260715
-4.009299  -2.978115
2.493525  1.963710
-2.513661  2.642162
1.864375  -3.176309
-3.171184  -3.572452
2.894220  2.489128
-2.562539  2.884438
3.491078  -3.947487
-2.565729  -2.012114
3.332948  3.983102
-1.616805  3.573188
2.280615  -2.559444
-2.651229  -3.103198
2.321395  3.154987
-1.685703  2.939697
3.031012  -3.620252
-4.599622  -2.185829
4.196223  1.126677
-2.133863  3.093686
4.668892  -2.562705
-2.793241  -2.149706
2.884105  3.043438
-2.967647  2.848696
4.479332  -1.764772
-4.905566  -2.911070

结果为:

k=5时

k=6时

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法工程师的学习日志 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档