是解决聚类问题的一种经典算法,简单、快速。
对处理大数据集,该算法是相对可伸缩和高效率的。
因为它的复杂度是0 (nkt ) , 其中, n 是所有对象的数目, k 是簇的数目, t 是迭代的次数。通常k <
在簇的平均值被定义的情况下才能使用,这对于处理符号属性的数据不适用。
必须事先给出k(要生成的簇的数目),而且对初值敏感,对于不同的初始值,可能会导致不同结果。经常发生得到次优划分的情况。解决方法是多次尝试不同的初始值。
它对于“躁声”和孤立点数据是敏感的,少量的该类数据能够对平均值产生极大的影响
#导入包
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
#导入数据集
iris=pd.read_csv('iris.txt',header=None);
# print(iris)
#计算两个数据集之间的距离
def distEclued(arra,arrb):
d=arra-arrb;
dist=np.sum(np.power(d,2),axis=1);
return dist;
#编写自动生成的随机的质心
def suiji_zhixin(dataset,k):
n=dataset.shape[1];
data_min=dataset.iloc[:,:n-1].min();
data_max=dataset.iloc[:,:n-1].max();
#随机生成质心
data_cent=np.random.uniform(data_min,data_max,(k,n-1));
return data_cent;
# print(suiji_zhixin(iris,3))
#k-means聚类算法实现
def Kmeans(dataset,k,distmeans=distEclued,createCent=suiji_zhixin):
#dataset表示数据集
#k表示簇
#distmeans表示欧式距离
#createCent表示随机生成k个质心
m,n=dataset.shape;
#生成质心
centrods=createCent(dataset,k);
#构造容器3列。第一列存放每个点到质心的距离,第二列表示对应的质心
#第三列表示上一次对应的质心
clusterAssment=np.zeros((m,3))
clusterAssment[:,0]=np.inf;#第一列先设置无穷大
clusterAssment[:,1:3]=-1;#第二列和第三列设置为-1
#将数据集与容器相拼接
resault_set=pd.concat([dataset,pd.DataFrame(clusterAssment)],axis=1,ignore_index=True);
clusterchanged=True;
while clusterchanged:
#迭代循环
clusterchanged=False;
for i in range(m):
#计算每一个点到质心的距离
dist=distmeans(dataset.iloc[i,:n-1].values,centrods);
#将距离的最小值放入结果的第n列存放
resault_set.iloc[i,n]=dist.min();
#将最小距离的的索引放入结果的第n+1列存放
resault_set.iloc[i,n+1]=np.where(dist==dist.min())[0];
#.np.where(condition) 当where内只有一个参数时,那个参数表示条件,
# 当条件成立时,where返回的是每个符合condition条件元素的坐标
clusterchanged=not(resault_set.iloc[:,-1]==resault_set.iloc[:,-2]).all();
#all()表示所有,只要有一个是false则返回false
#否则返回true
if clusterchanged:
#cent_df表示对本次的结果的第n+1列(表示的是质心的位置)
cent_df=resault_set.groupby(n+1).mean();
#重新计算质心,找出每一个
centrods=cent_df.iloc[:,:n-1].values;
resault_set.iloc[:,-1]=resault_set.iloc[:,-2];
#返回质心和结果
return centrods,resault_set
#显示分类结果
test1_cent,test1_cluster=Kmeans(iris,3,distEclued,suiji_zhixin)
#test1=Kmeans(iris,3,distEclued,suiji_zhixin)
# print(test1)
# plt.scatter(test_cluster.iloc[:,0],test_cluster.iloc[:,1],c=test_cluster.iloc[:,-1])
# plt.scatter(test_cent[:,0],test_cent[:,1],color='red',marker='x',s=80)
# plt.show();
#导入测试集
test=pd.read_table('testSet.txt',header=None)
# print(test)
#显示测试集的分布
plt.scatter(test.iloc[:,0],test.iloc[:,1]);
# plt.show();
#假设是标签
ze=pd.DataFrame(np.zeros(test.shape[0]).reshape(-1,1))
# print(ze.head())
test_set=pd.concat([test,ze],axis=1,ignore_index=True)
# print(test_set.head())
test_cent,test_cluster=Kmeans(test_set,4)
# print(test_cent)
# print(test_cluster)
plt.scatter(test_cluster.iloc[:,0],test_cluster.iloc[:,1],c=test_cluster.iloc[:,-1])
plt.scatter(test_cent[:,0],test_cent[:,1],color='red',marker='x',s=80)
plt.show();
#误差计算
# print(test_cluster.iloc[:,3].sum())
# print("----------------")
# print(test1_cluster.iloc[:,5].sum())
#
#学习聚类曲线
def KleanCruve(dataset,cluster=Kmeans,k=10):
n=dataset.shape[1];
SSE=[];
for i in range(1,k):
centroids,result=cluster(dataset,i+1);
SSE.append(result.iloc[:,n].sum())
plt.plot(range(2,k+1),SSE,'--o');
plt.show();
return SSE;
print(KleanCruve(iris))