一、k-means聚类算法
k-means聚类属于比较基础的聚类算法,它的算法步骤如下
算法步骤:
(1) 首先我们选择一些类/组等数据,首先确定需要分组的数量k,并随机初始化数据中的K个中心点(中心点表示每种类别的中心,质心)。
(2) 对于数据集中的每个数据点计算这个数据点到中心点的距离,数据点距离哪个中心点最近就划分到哪一类中。
(3)得到分好的数据后,重新 计算每一类中中心点作为新的中心点(即质心)。 计算均方差:
对于样本集。"k均值"(k-means)算法就是针对聚类划分最小化平方误差:
其中是簇Ci的均值向量。从上述公式中可以看出,该公式刻画了簇内样本围绕簇均值向量的紧密程度,E值越小簇内样本的相似度越高。
(4) 重复以上步骤,直到每一类中心在每次迭代后均方差小于一定阈值。也可以多次随机初始化中心点,然后选择运行结果最好的一个。
下图演示了K-Means进行分类的过程:(菱形为每种类别的中心)
二、代码实现
1、不适用sklearn 实现的python代码
import re
import numpy as np
import random
import codecs
import matplotlib.pyplot as plt
#数据结构 cenList[]存放质心的列表 [ [x,y],[x,y],,,,[x,y]]
# cenDiction 字典 存放质心和对应的数据 格式为[0:[[x,y],[x,y],,,,[x,y]],1:[[x,y],,[x,y]],,,k:[[x,y],,,[x,y]]
# 字典的Key为第几个之心的编号
# dataSet 为数据的坐标
def getDistance(v1,v2):
dis = np.sqrt(np.sum(np.square(v1 - v2))) #计算两个数据之间的欧式距离
return dis
def loadData(File):
dataSet = list()
lines = codecs.open(File,'r','utf-8').readlines() #按行读取文件 并保存到列表中
for line in lines:
line = line.strip() #读取一行即一个数据点的坐标,去除前后多余空格
line = re.split(' ',line) # 根据空格分词 得到[‘x’,‘y’]形式
# aline = np.array(line)
coline = []
for i in line: #因从文件中读取的数据为str格式为方便后续运算转换成float的类型
num = float(i)
coline.append(num) #每个数据坐标存储为[x,y]格式
dataSet.append(coline)
return dataSet #dataSet为[[x1,y1],[x2,y2],,,,,[xn,yn]]格式
def innitCentroid(dataSet,k):
return random.sample(dataSet,k) #初始化质心
def getCentroid(cenList,cenDiction): #计算每个类别中的质心
newcen = list()
for i in range(len(cenList)):
newcen.append(np.mean(np.array(cenDiction[i]),0).tolist()) #对于每个类别 计算所有坐标的平均值
print('新的质心',newcen)
return newcen
def minDistance(dataSet,cenList): #计算最小聚类,获得新的分类
cenDiction = {}
for item in dataSet:
mind = float("inf") #最大数
flag = 0
aitem = np.array(item) #list类型不能对数据进行运算 所以转换为array类型
for i in range(len(cenList)): #对于每个之心 计算数据点到质心的距离
acen = np.array(cenList[i])
if getDistance(aitem,acen) < mind:
mind = getDistance(aitem,acen)
flag = i
if flag not in cenDiction.keys(): #如果质心不再分类字典的keys()中 加入
cenDiction[flag] = []
cenDiction[flag].append(item)
return cenDiction
def getDeviation(cenList,cenDiction): #计算均方差
sum = 0
for i in range(len(cenList)):
item = cenList[i]
aitem = np.array(item)
for data in cenDiction[i]:
adata = np.array(data)
sum = sum + getDistance(aitem,adata)
return sum
def showplot(cenList,cenDiction):
colormark = ['or','og','ob','ok','oy','ow'] #o表示圆 d表示菱形
cenmark = ['dr','dg','db','dk','dy','dw']
plt.figure('k-means聚类')
for i in range(len(cenList)):
plt.plot(cenList[i][0],cenList[i][1],cenmark[i])
for item in cenDiction[i]:
plt.plot(item[0],item[1],colormark[i])
plt.show()
if __name__ == '__main__':
inFile = 'E:/pythontest/km.txt'
dataSet = loadData(inFile)
cenList = innitCentroid(dataSet,4) #初始化质心
print('第1次迭代')
cenDiction = minDistance(dataSet,cenList) #计算最小聚类 分类
showplot(cenList, cenDiction)
oldnum = 0.0001
newnum = getDeviation(cenList,cenDiction) #计算均方差
k = 2
while abs(newnum - oldnum) > 0.0001: #当新旧均方差相差小于等于0.001 结束
cenList = getCentroid(cenList,cenDiction) #计算新的质心
cenDiction = minDistance(dataSet,cenList) #重新分类
oldnum = newnum
newnum = getDeviation(cenList,cenDiction)
print('第',k,'次迭代')
showplot(cenList, cenDiction)
k = k + 1
print('均方差',oldnum,newnum)
print('聚类完成')
2、使用python中的sklearn包实现聚类
自带函数:
sklearn.cluster.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:簇的个数,即你想聚成几类
- init: 初始簇中心的获取方法
- n_init: 获取初始簇中心的更迭次数,为了弥补初始质心的影响,算法默认会初始10次质心,实现算法,然后返回最好的结果。
- max_iter: 最大迭代次数(因为kmeans算法的实现需要迭代)
- tol: 容忍度,即kmeans运行准则收敛的条件
- precompute_distances:是否需要提前计算距离,这个参数会在空间和时间之间做权衡,如果是True 会把整个距离矩阵都放到内存中,auto 会默认在数据样本大于featurs*samples 的数量大于12e6 的时候False,False 时核心实现的方法是利用Cpython 来实现的
- verbose: 冗长模式
- random_state: 随机生成簇中心的状态条件。
- copy_x: 对是否修改数据的一个标记,如果True,即复制了就不会修改数据。bool 在scikit-learn 很多接口中都会有这个参数的,就是是否对输入数据继续copy 操作,以便不修改用户的输入数据。这个要理解Python 的内存机制才会比较清楚。
- n_jobs: 并行设置
- algorithm: kmeans的实现算法,有:’auto’, ‘full’, ‘elkan’, 其中 ‘full’表示用EM方式实现
代码如下:
from sklearn.cluster import KMeans
from sklearn.externals import joblib
import numpy
import time
import matplotlib.pyplot as plt
if __name__ == '__main__':
## step 1: 加载数据
print("step 1: load data...")
dataSet = []
fileIn = open('E:/pythontest/km.txt')
for line in fileIn.readlines():
lineArr = line.strip().split(' ')
dataSet.append([float(lineArr[0]), float(lineArr[1])])
#设定不同k值以运算
for k in range(2,10):
clf = KMeans(n_clusters=k) #设定k !!!!!!!!!!这里就是调用KMeans算法
s = clf.fit(dataSet) #加载数据集合
numSamples = len(dataSet)
centroids = clf.predict(dataSet)
#centroids = clf.fit_predict(dataSet)
# centroids = clf.labels_
print(centroids,type(centroids)) #显示中心点
print(clf.inertia_ ) #显示聚类效果
mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
#画出所有样例点 属于同一分类的绘制同样的颜色
for i in range(numSamples):
#markIndex = int(clusterAssment[i, 0])
plt.plot(dataSet[i][0], dataSet[i][1], mark[clf.labels_[i]]) #mark[markIndex])
mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']
# 画出质点,用特殊图型
centroids = clf.cluster_centers_
for i in range(k):
plt.plot(centroids[i][0], centroids[i][1], mark[i], markersize = 12)
#print centroids[i, 0], centroids[i, 1]
plt.show()
部分参考https://blog.csdn.net/sinat_26917383/article/details/70240628