版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013317445/article/details/87931606
k-Means是一种无监督的聚类算法,实现起来比较简单,聚类效果也不错,因此被广泛应用。
原理
物以类聚,人以群分。
无监督 聚类。
简单地说,就是把相似的物体聚到一个簇。同一簇内相似度尽可能大,不同簇间相似度尽可能低。采用距离度量相似程度。
算法
1、初始化k个中心点,有了k个簇
2、对所有样本,计算每个样本与k个中心点的距离,将各样本划分到距离最近的中心点所在的簇
3、重新计算各簇的中心:为各簇所有点的均值
4、不断迭代2、3,直到各簇不再发生变化或者达到迭代次数
优缺点
优点:
是解决聚类问题的一种经典算法,简单、快速;
对处理大数据集,该算法高效率;
当结果是密集的,它的效果较好。
缺点:
k值选取不好把握;
对初值敏感(初始聚类中心的选择:改进1:k-means++,改进2:二分k-means);
对噪声和异常点敏感(改进:离群点检测,去掉离群点后再聚类,减少它们对聚类效果的影响);
只能收敛到局部最小,不适合于发现非凸形状的簇还有,不能处理大小、密度差别很大的簇(改进:基于密度的聚类:擅于解决不规则形状的聚类问题,能克服基于距离的算法只能发现“类圆形”的聚类的缺点。如,DBSCAN算法)
实现
import numpy as np
#文件解析,将值封装到矩阵(实质是list里每个元素list)里
#dataset文件每行数字以制表符分
def loadDataset(filename):
data = []
f = open(filename)
for line in f:
line = line.strip().split('\t')
floatline = map(float, line)
data.append(floatline)
return data
#欧式距离公式
def distance(vecA, vecB):
return np.sqrt(np.sum(np.square(vecA - vecB)))
#构建质心
#随机选择k个样本点做质心
def randCenter(dataMat, k):
row, col = dataMat.shape
centers = []
centersIndex = np.random.randint(0, row, size=k)
for i in centersIndex:
centers.append(dataMat[i])
centers = np.mat(centers)
return centers
#输入:样本点集合(矩阵形式,m个样本),聚类簇数k
# 算法:
# 随机选择k个样本作为初始质心:{u1,u2,..uk},即均值向量集合
# 1、对每一个点:
# 计算它与每一个簇的质心的距离;
# 找出最小距离;
# 划分到最小距离所在簇
# (所有点都被划分了一遍)
# 2、对每一个簇:
# 重新计算质心(均值向量)
# 如果质心改变了,则更新质心;否则,不用更新
# 直到当前的所有簇的质心均未改变,算法结束【换个思路:即是如果一有改变就继续循环1、2】
# 返回:质心、簇划分
def kmeans(dataMat, k):
m = dataMat.shape[0] #也就是row,m个样本点
centers= randCenter(dataMat, k)
#簇划分 初始时为:{0:u1, 1:u2,..., k:uk}
clusters = {}
for cent in range(k):
clusters[cent]= centers[cent]
clusterChanged = True
while clusterChanged:
clusterChanged= False
for i in range(m):
minDist= distance(dataMat[i], centers[0])
minIndex= 0
for j in range(k):
distIJ= distance(dataMat[i], centers[j])
if distIJ< minDist:
minDist= distIJ
minIndex= j
#将样本点划分到最近簇
clusters[minIndex]= np.row_stack((clusters[minIndex], dataMat[i])) #minIndex键下的值——矩阵增一行
#一轮划分完后(即所有样本划分一遍后),计算质心
for cent in range(k):
newCenter= np.mat([clusters[cent][:,0].mean(), clusters[cent][:,1].mean()])
if newCenter[cent, 0]!= centers[cent, 0] or newCenter[cent, 1]!= centers[cent, 1]:
clusterChanged= True
#更新质心
centers[cent]= newCenter
return centers, clusters