import numpy as np #导入numpy包,且起名为np
'''numpy是Python中科学计算的基础包,它是一个Python库,提供多维数组对象,
各种派生对象,如掩码数组和矩阵以及用于数组快速操作的各种例程。'''
import matplotlib.pyplot as plt #导入matplotlib库中的pyplot包,并起名为plt
'''(matplotlib.pyplot 是命令行风格的函数集,
让matplotlib看起来像MATLAB.Each一样工作。
pyplot函数能够对画布(figure)进行一些改变,例如:创建一个画布(figure),
在画布中创建一个绘图区域,在绘图区域中画图,使用文字标签修饰图形。)'''
def L2(vecXi, vecXj):
'''输入:向量vecXi,向量vecXj
输出:两个向量的欧式距离
描述:计算两个向量的欧式距离
计算欧氏距离
para vecXi:点坐标,向量
para vecXj:点坐标,向量
return: 两点之间的欧氏距离(距离标量)'''
return np.sqrt(np.sum(np.power(vecXi - vecXj, 2)))
#np.sqrt(x):计算数组各元素的平方根,括号里的数必须大于或等于0。
#numpy中的sum则可以求出矩阵或数组所有元素的和
#np.power(x, y) 表示x 的y次方,
# y=2表示x的平方,y=1/2表示x开方,y =1/3表示x开立方,y= -1表示x的倒数。
def kMeans(S, k, distMeas=L2):
'''输入:数据集,k,计算向量间距离的函数名,随机生成k个随机质心的函数名
输出:包含质心的集合,包含K个随机质心(clusterCents)的集合,簇分配结果矩阵
描述:kmeans算法实现
K均值聚类
para S:样本集,多维数组(样本数据集,np数组)
para k:簇个数
para distMeas:距离度量函数,默认为欧氏距离计算函数
return sampleTag:一维数组,存储样本对应的簇标记
return clusterCents:一维数组,各簇中心
retrun SSE:误差平方和'''
#m:获取数据集行数用于后边初始化全0矩阵clusterCents
m = np.shape(S)[0] #样本总数(数据集的行数,即数据的个数)
sampleTag = np.zeros(m)
# 随机产生k个初始簇中心
n = np.shape(S)[1] # 样本向量的特征数()
#clusterCents:用于保存结果矩阵
clusterCents = np.mat([[-3.38822792,-1.75282590],
[5.65622583,7.53046709],[10.64183154,0.20088133]])
#clusterCents = np.mat(np.zeros((k,n)))
#for j in range(n):
# minJ = min(S[:,j])
# rangeJ = float(max(S[:,j]) - minJ)
# clusterCents[:,j] = np.mat(minJ + rangeJ * np.random.rand(k,1))
sampleTagChanged = True
SSE = 0.0
while sampleTagChanged: # 如果没有点发生分配结果改变,则结束
sampleTagChanged = False
SSE = 0.0
# 计算每个样本点到各簇中心的距离
for i in range(m):
# 开始 循环 为每一个数据点 分配到距离其最近的类中心
minD = np.inf# 初始化最小距离为inf(无穷大) 索引为负
# 开始针对当前数据点 计算其到每个类质心最短的距离 保存最小的距离
minIndex = -1
for j in range(k): #对于每一质心
# 注意以行为开头 即 行向量 即对每个数据点计算其到每个类中心点的欧氏距离
d = distMeas(clusterCents[j,:],S[i,:]) #得到数据与质心间的距离
# 每次进行判断是否比上次距离更小 进行存储更小的距离
# 直至比较到最后取到最小距离 【不保存所有距离,只保存最小距离】
if d < minD: #更新最小值
minD = d
minIndex = j
# 如果索引即 该数据点的归属类(簇)发生了改变 就继续进行循环
if sampleTag[i] != minIndex:
sampleTagChanged = True
# 此时再进行更新该数据点的(索引)归属类,和距离该归属类质(或中)心最小距离。
sampleTag[i] = minIndex
SSE += minD**2
print(clusterCents)
plt.scatter(clusterCents[:,0].tolist(),clusterCents[:,1].tolist(),
c='blue',marker='*',linewidths=7)
#plt.scatter()绘制散点图 【c:颜色(默认是蓝色'b');
#marker:标记(点的形状)(默认的是'o')
#linewidths:也就是标记点的长度。】
plt.scatter(S[:,0],S[:,1],c=sampleTag,
linewidths=np.power(sampleTag+0.5, 2))
plt.show()
print(SSE)
# 重新计算簇中心
for i in range(k): #对于每一个簇
# 下面用于找到 当前类质心 下的所有数据点
ClustI = S[np.nonzero(sampleTag[:]==i)[0]]
#通过数组过滤得到簇中所有数据
clusterCents[i,:] = np.mean(ClustI, axis=0)
#将质心更新为簇中所有数据的均值
#axis=0表示沿矩阵的列方向计算均值
return clusterCents, sampleTag, SSE
if __name__=='__main__':
samples = np.loadtxt("kmeansSamples.txt") #调用numpy的包
clusterCents, sampleTag, SSE = kMeans(samples, 3) #调用kMeans函数
#plt.scatter(clusterCents[:,0].tolist(),
# clusterCents[:,1].tolist(),c='r',marker='^')
#plt.scatter(samples[:,0],samples[:,1],c=sampleTag,
# linewidths=np.power(sampleTag+0.5, 2))
plt.show()
print(clusterCents)
print(SSE)
运行结果:
相关链接