前一节贴了我自己写的代码,写完后我又看了书上的代码,并将它复现了一遍。两个代码的思想基本一致,只在部分地方有所区别。
import numpy as np
import random
#载入数据
#filename:文件名
def loadDataSet(filename):
dataMat = []
fr = open(filename)
for line in fr.readlines():
curLine = line.strip().split('\t')
fitLine = list(map(float,curLine))
dataMat.append(fitLine)
dataMat = np.mat(dataMat)
return dataMat
#距离计算函数
#vecA,vecB:计算距离的两个行向量
#我的函数这里传递的是数据集和质点集以及对应的行,这里却直接传递了需要进行计算的向量
def distEclud(vecA,vecB):
return np.sqrt(np.sum(np.power(vecA - vecB,2)))
#初始随机质点选择
#dataSet:数据集
#k:指定质点数
#我这里用的方法是初始化一个k行数据列数列的零矩阵,然后用random()乘以数据行数并向上取
#整(避免取到第0个),这样是使用数据点作为初始质点。书里的做法是计算出数据每一列的上下
#界,然后随机在这个界限内取值,作为初始质点。这总方法应该更好一点,因为选取的质点可能
#更加均匀,且在处理类别间数量差异大的数据时,效果会更好
def randCent(dataSet,k):
n = np.shape(dataSet)[1]
centroids = np.mat(np.zeros((k,n)))
for j in range(n):
minJ = np.min(dataSet[:,j])
rangeJ = float(np.max(dataSet[:,j]) - minJ)
centroids[:,j] = minJ + rangeJ * random.random()*k
return centroids
#k-均值聚类函数
#dataSet:数据集
#distMeas:距离计算函数,默认使用平方差方法计算距离
#creatCent:初始质点创建函数,默认使用randCen()
def kMeans(dataSet,k,distMeas = distEclud,createCent = randCent):
m = np.shape(dataSet)[0]
#数据的类别及与所属类别的质点的距离矩阵。我是创建了一个新的m行(n+2)列矩阵,前n列是数
#据,后2列和这个矩阵相同。我的方法大概更直观些,且可以少记一个变量名。这里的方法使程
#序更简洁
clusterAssment = np.mat(np.zeros((m,2)))
#得到初始质点矩阵
centroids = createCent(dataSet,k)
#检查是否有数据点改变了类别
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(m):
minDist = np.inf
minIndex = -1
for j in range(k):
distJI = distMeas(centroids[j,:],dataSet[i,:])
if distJI < minDist:
minDist = distJI
minIndex = j
#若与该数据点距离最近的质点所属类别与该数据的类别不同,则更新标记置为真
if clusterAssment[i,0] != minIndex: clusterChanged = True
clusterAssment[i,:] = minIndex,minDist ** 2
print (centroids)
#将同一类别内的所有数据取平均作为新的质点数据。我这里是遍历数据,并记录类别内数据
#数及数据之和,然后用前者除以后者,虽然结果也可以,但不如这里的方法的简洁和优雅
for cent in range(k):
ptsInClust = dataSet[np.nonzero(clusterAssment[:,0].A == cent)[0]]
centroids[cent,:] = np.mean(ptsInClust,axis = 0)
return centroids,clusterAssment
if __name__ == '__main__':
dataMat = loadDataSet('testSet.txt')
myCentroids,clustAssing = kMeans(dataMat,4)
print(myCentroids,clustAssing)