实验内容
1. 实验基本原理及目的
K-means(K-均值):
K-均值算法把簇形心定义为簇内点的均值
算法的基本思想:
首先,随机的选择k个对象,每个对象初始的代表了一个簇的平均值;
对剩余的每个对象,根据其与各个簇中心的距离,将它赋给最近的簇;
然后重新计算每个簇的平均值。
这个过程不断重复,直到准则函数收敛。
2. 数据的准备及数据预处理
将数据读入,然后将数据转化为numpy形式,进行归一化处理,这里采用的是0-1归一化。
3. 实验过程
1. 函数介绍:
read(datafile):数据预处理函数,datafile为文件所在位置,返回值为data,为一个numpy类型的数组。
distEclud(vecA, vecB):计算欧式距离的函数,vecA,vecB分别为两个向量,返回值为他们之间的距离。
CenterPoints(dataSet, k):初始点函数,在dataSet中选取K个点作为初始中心点,返回值为一个矩阵,每个行向量为选取的中心点。
K_means(dataSet,k,distMeans=distEclud,createCent=CenterPoints):K—mean聚类函数,dataSet为数据集,k为聚类的个数,distMeans表示距离,createCent表示初始点选择。返回值为最后的中心点,以及分类情况。
transfer(data,clustAssing):将data按照分类结果clustAssing分为三个组,以便于画图,返回值为三个簇的点。
plot(Point1,Point2,Point3):画图函数,输入值为三个簇的点,将聚类结果进行可视化展示。
2.源码
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
import random
import matplotlib.pyplot as plt
#预处理数据,做0-1规范化处理
def read(datafile):
df=pd.read_excel(datafile)
df.index=df['国家']
df=df.drop(['国家'],axis=1)
df=pd.DataFrame(df,dtype=np.float)
for i in df.columns:
dfmax=max(df[i])
dfmin=min(df[i])
for j in df.index:
df[i][j]=(df[i][j]-dfmin)/(dfmax-dfmin)
data=np.array(df)
return data
#计算两个向量的欧氏距离
def distEclud(vecA, vecB):
return np.sqrt(np.sum(np.square(vecA-vecB)))
# 构建聚簇中心,取k个(此例中为3)随机质心
def CenterPoints(dataSet, k):
m,n=np.shape(dataSet)
centroids = np.mat(np.zeros((k,n))) # 每个质心有n个坐标值,总共要k个质心
a=random.sample(list(np.arange(m)),k)
for i in range(0,k):
centroids[i,:]=dataSet[a[i],:]
return centroids
def K_means(dataSet,k,distMeans=distEclud, createCent=CenterPoints):
m=len(dataSet)
clusterAssment=np.mat(np.zeros((m,2)))# 用于存放该样本属于哪类及质心距离
# clusterAssment第一列存放该数据所属的中心点,第二列是该数据到中心点的距离
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=distMeans(centroids[j,:],dataSet[i,:])
if DistJI<minDist:# 如果第i个数据点到第j个中心点更近,则将i归属为j
minDist=DistJI
minIndex=j
if clusterAssment[i,0] != minIndex:#如果分配发生变化,则需要继续迭代
clusterChanged = True;
clusterAssment[i,:] = minIndex,minDist**2#并将第i个数据点的分配情况存入字典
print(centroids)
for cent in range(k):# 重新计算中心点
ptsInClust=dataSet[np.nonzero(clusterAssment[:,0].A==cent)[0]]#去第一列等于cent的所有列
centroids[cent,:]=np.mean(ptsInClust, axis = 0)#算出这些数据的中心点
return centroids, clusterAssment
#将三类点分开
def transfer(data,clustAssing):
Point1=[]
Point2=[]
Point3=[]
m=len(data)
for i in range(m):
if clustAssing[i,0]==0:
Point1.append(data[i,:])
elif clustAssing[i,0]==1:
Point2.append(data[i,:])
else:
Point3.append(data[i,:])
return Point1,Point2,Point3
def plot(Point1,Point2,Point3):
fig = plt.figure()
ax= fig.add_subplot(111, projection ='3d')
ax.scatter(Point1[:,0],Point1[:,1],Point1[:,2],c='y')
ax.scatter(Point2[:,0],Point2[:,1],Point2[:,2],c='r')
ax.scatter(Point3[:,0],Point3[:,1],Point3[:,2],c='g')
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
plt.show()
datafile='D:/ProgramData/file8/data.xls'
data=read(datafile)
lastCenterPoint,clustAssing=K_means(data,3)
print('最后的中心点:')
print(lastCenterPoint)
print('聚类结果:')
print(clustAssing)
Point1,Point2,Point3=transfer(data,clustAssing)
plot(np.array(Point1),np.array(Point2),np.array(Point3))
4. 实验结果分析
输出结果:
最终三个中心点以及聚类结果:
输出的三维聚类图:
分析:
选取不同的初始点,聚类结果有所差别,由结果可知中国队处于三流水平。