以下代码为简单的随机k-均值聚类法,距离计算方法为平方差
import numpy as np
import random
import math
#载入数据
#filename:载入文件名
def loadDataSet(filename):
dataSet = []
fr = open(filename)
for line in fr.readlines():
mat0 = line.strip().split('\t')
mat1 = list(map(float,mat0))
dataSet.append(mat1)
return dataSet
#随机选取k个点作为起始质点
#dataSet:数据集
#k:指定聚类数
#Clu:初始化的质点矩阵
#initClu:最初的选取质点矩阵:防止选取重复初始质点
def initClu(dataSet,k):
m,n = np.shape(np.mat(dataSet))
Clu = np.zeros((k,n))
initClu = np.zeros((k,1)).astype(int)
#检查是否重复
check = 0
for i in range(k):
newClu = math.ceil(random.random()*m)
for j in range(k):
checkClu = initClu[j][0]
#如果检查完当前存储的质点,则跳出循环
if checkClu == 0:
break
#若出现重复,则报错(本来打算i--,但是发现python的for循环的i的变化对循环没有影响,于是选择报错
if newClu == checkClu:
raise Exception("Invalid Cluster!")
else:
#存储当前质点及数据
initClu[i] = newClu
Clu[i] = dataSet[newClu]
return Clu
#聚类函数
#dataSet:数据集
#k:制定聚类数
#inDat:带有自身类别inDat[][-2]和与质点距离inDat[][-1]的数据矩阵
def kMean(dataSet,k):
#得到初始化质点矩阵
Clu = initClu(dataSet,k)
#检查是否有点的类别变化
check = True
m,n = np.shape(dataSet)
inDat = np.zeros((m,n+2))
inDat[:,0:n] = dataSet
while(check):
check = False
for i in range(m):
bestClu = inDat[i][-2]
bestDis = inDat[i][-1]
#若距离为0,说明未将该数据归类,则初始化距离及类别
if(bestDis == 0.0):
bestDis = 10000
bestClu = -1
for j in range(k):
#计算数据点与质点距离
dis = calDis(inDat,i,Clu,j)
if dis < bestDis :
check = True
bestDis = dis
bestClu = j
#更新最短距离
inDat[i][-2] = bestClu
inDat[i][-1] = bestDis
#重新计算各质点数据
for j in range(k):
#求和矩阵
sumMat = np.zeros((1, n))
sum = 0
for i in range(m):
if inDat[i][-2] == j :
sumMat += dataSet[i][:]
sum += 1
print(inDat[i][-2],j,sum)
Clu[j] = sumMat / sum
return Clu
#距离计算函数
#inDat:数据矩阵
#i:数据点位置
#Clu:质点矩阵
#j:质点位置
def calDis(inDat,i,Clu,j):
sum = 0.0
m,n = np.shape(inDat)
for k in range(n-2):
sum += np.power((inDat[i][k] - Clu[j][k]),2)
return sum
if __name__ == '__main__':
dataSet = loadDataSet('testSet.txt')
Clu = []
Clu = kMean(dataSet,4)
print(Clu)
函数的思想还是很简单的,首先随机选取k个数据点作为初始质点(k的个数由程序员指定),然后计算每个数据点到各个质点的距离,并将其归类于距离最近的那个质点所在的聚类。一轮迭代后,计算所有聚类内数据的均值作为新的质点(此时的质点已经不再是数据点),并重复这一步骤,直到不再有数据点的类别发生变化,则认为分类完成。
这种方法的优点在于,因为是非监督分类,所以无需了解数据的分布和特性,也无需对其进行训练。缺点在于k值的选取很影响分类结果,且分类精度可能不如监督分类。
这种方法我认为可以提升的地方在于,使用科学的方法来得到k,或者在迭代中根据分类情况改变k的取值。以及在不同的应用里,选取合适的距离计算方法,对分类精度的提升应该都有帮助。