目录

0. 前言

1. K-means

2. K-means的后处理

3. 二分K-means

4. K 的选择

5. 实战案例

5.1. 原始K-means

5.2. 二分K-means


学习完机器学习实战的K-means,简单的做个笔记。文中部分描述属于个人消化后的理解,仅供参考。

本篇综合了先前的文章,如有不理解,可参考:

吴恩达机器学习(十一)K-means

所有代码和数据可以访问 我的 github

如果这篇文章对你有一点小小的帮助,请给个关注喔~我会非常开心的~

0. 前言

算法有监督学习和无监督学习之分:

  • 监督学习(supervised learning):训练集合已全部标注所属类别或者目标结果
  • 无监督学习(unsupervised learning):训练集合未进行标注,无法预先知道每个数据的所属类别或者目标结果

聚类(clustering)是一种无监督学习,将相似的对象归到同一个簇(cluster)中。簇内对象越相似,聚类效果越好。

聚类可以采用多种不同的方法计算一个簇中的相似程度。K-means(K-均值)采用的就是数据与簇中心的欧式距离度量相似程度,簇中心由一个簇中数据的均值构成。

  • 优点:容易实现
  • 缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢
  • 适用数据类型:数值型数据

1. K-means

K-means, 为用户定义的簇的个数,每一个簇通过其中心(质心)表示。

K-means的算法可表示为:

  1. 随机创建  个簇的质心
  2. 簇分配:将数据集中每一个点分配到距离最近的簇中
  3. 移动聚类中心:重新计算每个簇的中心,更新为该簇所有点的平均值
  4. 继续进行簇分配和移动聚类中心,直到没有数据点的分配结果发生改变为止

2. K-means的后处理

在K-means中,采用误差平方和(SSE,sum of squared error)度量聚类效果:

其中, 表示当前样本所属的簇的质心的向量。

K-means聚类算法有时候会陷入局部最优值,如下图所示(图源:吴恩达机器学习):

为避免局部最优,有几种方法:

  1. 可在上述算法外再嵌套一层循环,每次确定簇中心之后计算SSE,多次迭代之后,选择SSE最小的一组结果
  2. 将具有最大SSE的簇运用K-means划分为两个簇,然后再合并最近的质心,或者合并两个使SSE增幅最小的质心

注:聚类的目标是在保持簇数目不变的情况下提高簇的质量。

3. 二分K-means

为解决K-means算法的局部最优问题,可采用二分K-means。

二分K-means的思想是,首先只有一个簇,所有的数据属于当前簇,然后运用K-means将簇分为两个簇,再选择其中一个簇,对其进行K-means将其分为两个,直到达到用户指定的簇数目。

在选择簇的思想中,主要有两种:

  1. 选择划分后可以最大程度降低SSE的簇
  2. 选择当前SSE最大的簇进行划分

4. K 的选择

簇的数量的选择,通常有两种方法,均要求  :

  • 人工选择:根据需求或者已知的知识,进行人工选择簇的数量
  • 肘部法则:如下图所示(图源:吴恩达机器学习),尝试不同的  ,选择变化率明显变缓的“肘部点”

5. 实战案例

以下将展示书中案例的代码段,所有代码和数据可以在github中下载:

5.1. 原始K-means

# coding:utf-8
from numpy import *"""
原始k-means
"""# 加载数据集
def loadDataSet(fileName):dataMat = []fr = open(fileName)for line in fr.readlines():curLine = line.strip().split('\t')fltLine = list(map(float, curLine))dataMat.append(fltLine)return dataMat# 向量的欧式距离
def distEclud(vecA, vecB):return sqrt(sum(power(vecA - vecB, 2)))# 随机生成k个质心
def randCent(dataSet, k):n = shape(dataSet)[1]# K个质心的向量centroids = mat(zeros((k, n)))for j in range(n):minJ = min(dataSet[:, j])rangeJ = float(max(dataSet[:, j]) - minJ)centroids[:, j] = mat(minJ + rangeJ * random.rand(k, 1))return centroids# k-means算法
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):m = shape(dataSet)[0]# 每个数据对应的簇和距离clusterAssment = mat(zeros((m, 2)))# 随机生成k个质心centroids = createCent(dataSet, k)clusterChanged = Truewhile clusterChanged:clusterChanged = False# 遍历每一个数据for i in range(m):minDist = infminIndex = -1# 遍历每一个质心for j in range(k):distJI = distMeas(centroids[j, :], dataSet[i, :])if distJI < minDist:minDist = distJIminIndex = j# 当前数据的质心改变if clusterAssment[i, 0] != minIndex:clusterChanged = True# 记录当前质心和距离clusterAssment[i, :] = minIndex, minDist ** 2# print(centroids)# 重新计算每个质心的位置for cent in range(k):# 获取属于当前簇的数据ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]# 按列求平均,重新计算质心位置centroids[cent, :] = mean(ptsInClust, axis=0)return centroids, clusterAssmentif __name__ == '__main__':datMat = mat(loadDataSet('testSet.txt'))myCentroids, clusterAssing = kMeans(datMat, 4)print(myCentroids)

5.2. 二分K-means

# coding:utf-8
from numpy import *
import matplotlib
import matplotlib.pyplot as plt"""
二分k-means
"""# 向量的欧式距离
def distEclud(vecA, vecB):return sqrt(sum(power(vecA - vecB, 2)))# 随机生成k个质心
def randCent(dataSet, k):n = shape(dataSet)[1]# K个质心的向量centroids = mat(zeros((k, n)))for j in range(n):minJ = min(dataSet[:, j])rangeJ = float(max(dataSet[:, j]) - minJ)centroids[:, j] = mat(minJ + rangeJ * random.rand(k, 1))return centroids# k-means算法
def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):m = shape(dataSet)[0]# 每个数据对应的簇和距离clusterAssment = mat(zeros((m, 2)))# 随机生成k个质心centroids = createCent(dataSet, k)clusterChanged = Truewhile clusterChanged:clusterChanged = False# 遍历每一个数据for i in range(m):minDist = infminIndex = -1# 遍历每一个质心for j in range(k):distJI = distMeas(centroids[j, :], dataSet[i, :])if distJI < minDist:minDist = distJIminIndex = j# 当前数据的质心改变if clusterAssment[i, 0] != minIndex:clusterChanged = True# 记录当前质心和距离clusterAssment[i, :] = minIndex, minDist ** 2# print(centroids)# 重新计算每个质心的位置for cent in range(k):# 获取属于当前簇的数据ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]# 按列求平均,重新计算质心位置centroids[cent, :] = mean(ptsInClust, axis=0)return centroids, clusterAssment# 二分k-means
def biKmeans(dataSet, k, distMeas=distEclud):m = shape(dataSet)[0]# 所有数据属于的簇和与簇质心的距离clusterAssment = mat(zeros((m, 2)))# 初始化第一个簇centroid0 = mean(dataSet, axis=0).tolist()[0]# 簇列表centList = [centroid0]# 计算每一个数据与当前唯一簇的距离for j in range(m):clusterAssment[j, 1] = distMeas(mat(centroid0), dataSet[j, :]) ** 2# 循环执行二分,直到簇的数量达到kwhile (len(centList) < k):lowestSSE = inf# 遍历每一个簇for i in range(len(centList)):# 获取属于当前簇的数据ptsInCurrCluster = dataSet[nonzero(clusterAssment[:, 0].A == i)[0], :]# 进行2-meanscentroidMat, splitClustAss = kMeans(ptsInCurrCluster, 2, distMeas)# 计算误差平方和sseSplit = sum(splitClustAss[:, 1])sseNotSplit = sum(clusterAssment[nonzero(clusterAssment[:, 0].A != i)[0], 1])print("sseSplit, and notSplit: ", sseSplit, sseNotSplit)# 如果小于最小误差,则替换if (sseSplit + sseNotSplit) < lowestSSE:# 最佳划分簇bestCentToSplit = i# 新的两个簇向量bestNewCents = centroidMat# 原先属于最佳划分簇的数据,当前属于的新簇和距离bestClustAss = splitClustAss.copy()# 最低的误差平方和lowestSSE = sseSplit + sseNotSplit# 将划分后,数据属于新簇的簇索引# 由0, 1改为bestCentToSplit和len(centList)bestClustAss[nonzero(bestClustAss[:, 0].A == 1)[0], 0] = len(centList)bestClustAss[nonzero(bestClustAss[:, 0].A == 0)[0], 0] = bestCentToSplitprint('the bestCentToSplit is: ', bestCentToSplit)print('the len of bestClustAss is: ', len(bestClustAss))# 修改被划分的簇的质心,添加新的簇centList[bestCentToSplit] = bestNewCents[0, :].tolist()[0]centList.append(bestNewCents[1, :].tolist()[0])# 取属于被划分簇的那些数据,修改这些数据的新的簇和到簇质心的距离clusterAssment[nonzero(clusterAssment[:, 0].A == bestCentToSplit)[0], :] = \bestClustAss  # reassign new clusters, and SSEreturn mat(centList), clusterAssment# 球面余弦定理
def distSLC(vecA, vecB):a = sin(vecA[0, 1] * pi / 180) * sin(vecB[0, 1] * pi / 180)b = cos(vecA[0, 1] * pi / 180) * cos(vecB[0, 1] * pi / 180) * \cos(pi * (vecB[0, 0] - vecA[0, 0]) / 180)return arccos(a + b) * 6371.0# 聚类,画图
def clusterClubs(numClust=5):datList = []# 加载数据集for line in open('places.txt').readlines():lineArr = line.split('\t')datList.append([float(lineArr[4]), float(lineArr[3])])datMat = mat(datList)# 二分k-meansmyCentroids, clustAssing = biKmeans(datMat, numClust, distMeas=distSLC)# 创建画板fig = plt.figure()rect = [0.1, 0.1, 0.8, 0.8]scatterMarkers = ['s', 'o', '^', '8', 'p', \'d', 'v', 'h', '>', '<']axprops = dict(xticks=[], yticks=[])# 创建底图# 每一个axes都是一个独立的图层ax0 = fig.add_axes(rect, label='ax0', **axprops)imgP = plt.imread('Portland.png')ax0.imshow(imgP)# 创建数据图层ax1 = fig.add_axes(rect, label='ax1', frameon=False)# 画每一个簇的数据for i in range(numClust):ptsInCurrCluster = datMat[nonzero(clustAssing[:, 0].A == i)[0], :]markerStyle = scatterMarkers[i % len(scatterMarkers)]ax1.scatter(ptsInCurrCluster[:, 0].flatten().A[0], ptsInCurrCluster[:, 1].flatten().A[0],marker=markerStyle, s=90)# 画簇的质心ax1.scatter(myCentroids[:, 0].flatten().A[0], myCentroids[:, 1].flatten().A[0], marker='+', s=300)plt.show()if __name__ == '__main__':clusterClubs(5)

如果这篇文章对你有一点小小的帮助,请给个关注喔~我会非常开心的~

机器学习实战(九)K-means(K-均值)相关推荐

  1. 统计学方法机器学习实战(二) K近邻算法

    目录 一.前言: 二.理论难点: 距离度量: 欧式距离: 三.数据可视化 四.数据归一化: 五.代码实践: 理论补充 实验一: 海伦约会 实验二 使用sklearn实现knn 六.总结 1.kNN算法 ...

  2. 《机器学习实战》——kNN(k近邻算法)

    原作者写的太好了,包括排版都特别整齐(其中有一个错误之处就是在约会网站配对效果判定的时候,列表顺序不对,导致结果有误,这里我已做出修改) 原作者和出处:http://blog.csdn.net/c40 ...

  3. k均值聚类算法(K Means)及其实战案例

    算法说明 K均值聚类算法其实就是根据距离来看属性,近朱者赤近墨者黑.其中K表示要聚类的数量,就是说样本要被划分成几个类别.而均值则是因为需要求得每个类别的中心点,比如一维样本的中心点一般就是求这些样本 ...

  4. 机器学习实战——K均值

    文章目录 1 K均值聚类算法 2 使用后处理来提高聚类性能 3 二分K-均值算法 4 示例:对地图上的点进行聚类 5 总结 6 补充 Supervised learning:目标变量实现存在 输入X, ...

  5. 刻意练习:机器学习实战 -- Task01. K邻近算法

    背景 这是我们为拥有 Python 基础的同学推出的精进技能的"机器学习实战" 刻意练习活动,这也是我们本学期推出的第三次活动了. 我们准备利用8周时间,夯实机器学习常用算法,完成 ...

  6. 我用Python把抖音上的美女图片转字符画,期望的AI目标更进一步【机器学习算法实战小项目,k聚类算法图片转化字符画】

    大家好,我是辣条. 最近在学习算法,今天给大家带来一个机器学习实战小项目 项目效果展示 学习目标 1.cv2转换图片数据  2.numpy提取图片矩阵数据  3.k均值算法获取图片的分类 工具使用 开 ...

  7. 机器学习与python实战(一)-k近邻

    kNN(k-nearest neighbor)算法是一个简单而经典的机器学习分类算法,通过度量"待分类数据"和"类别已知的样本"的距离对样本进行分类. from ...

  8. k近邻算法python解读_Python3《机器学习实战》学习笔记(一):k-近邻算法(史诗级干货长文)...

    运行平台: Windows IDE: Sublime text3 一.简单k-近邻算法 本文将从k-近邻 1.k-近邻法简介 k近邻法(k-nearest neighbor, k-NN)是1967年由 ...

  9. 机器学习实战---朴素贝叶斯算法实现+使用K折交叉验证(代码详解+创新)

    <机器学习实战朴素贝叶斯算法实现+使用K折交叉验证> 未经允许,不得擅自转载! 提供数据集如下(永久有效,需要的自行下载): 链接:https://pan.baidu.com/s/1Sv0 ...

  10. 《机器学习实战》萌新入门笔记 ① — — K近邻算法 趣味讲解和书本实例详细注释后代码

    开坑前言:大一在读新生开启了自己的机器学习之旅,从接触到现在已经有快两个月了,现在回过头为夯实基础,从开始看起<机器学习实战>这本书,即使是最简单的KNN算法,详细看过作者用python实 ...

最新文章

  1. 2021年大数据Flink(三十七):​​​​​​​Table与SQL ​​​​​​案例四
  2. echarts 点亮中国插件研究
  3. 机会是怎么变成陷阱的?
  4. 用树状数组解决求区间最值的问题:hdu1754
  5. neutron plugin 与 extension 编写流程
  6. zabbix 监控 Esxi
  7. MySQL的join类型
  8. django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询
  9. 三星Galaxy Note 10 Pro渲染图曝光:挖孔屏+前摄居中
  10. VTI介质Thomsen参数关于入射角的敏感性曲线
  11. tensorflow:激活函数(Activation Function)
  12. static成员变量的使用
  13. ardl模型stata命令_计量经济学《手把手教你EViews软件操作教程与案例分析》
  14. 微信公众号选择什么服务器好,微信开发选择订阅号还是服务号好?
  15. 新西兰梅西大学有计算机专业吗,【新西兰梅西大学计算机专业】 - 教外新西兰留学网...
  16. 在PS中快速制作发朋友圈的九宫格切图
  17. winmerge多个文件夹生成html,winmerge使用方法,winmerge使用教程
  18. 三段论_五项基本原则
  19. 高次osu(重邮第13届ACM程序设计大赛-网络赛)
  20. 【学习笔记】arduino mega2560 和 ESP8266WIFI模块 联合调试 ①

热门文章

  1. 在虚拟机中安装红旗桌面7.0 Linux操作系统的详细图文教程
  2. Selenium 生成HTML的测试报告
  3. EF ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象...
  4. 【原创】IDEA一定要改的八条配置
  5. git不区分文件名大小写这种坑当然要跳出来
  6. JavaScript基础知识(三个判断、三个循环)
  7. nodefs模块的使用demo
  8. 初步了解关于js跨域问题
  9. 除了随机还要进化——对Infinity进一步的想法
  10. 《为大量出现的KPI流快速部署异常检测模型》 笔记