K-means:无监督算法,具有不确定性,因为刚开始输入的聚类点不同,可能会导致最终聚类的结果不同,因此建议多做几次聚类,看看那种分类靠谱点。
- 簇的位置:簇中心的坐标。K-means初始化的时候随机选择一个点作为中心点,然后每个步骤迭代找到一个新的中心,在这个新的中心附近的点都相似,并被划分到同一个组;
- 簇的半径:簇内每个点到簇中心的距离的平方差;
- 簇的规模:簇内点的总数:
- 簇的密度:簇的规模和簇的半径的比值:
- 轮廓系数:用以评估聚类结果的好坏,它的值介于-1到1,负值说明簇的半径大于簇之间的距离,也就是说簇之间有重叠,说明聚类结果很差,1最好。
# -*- coding: utf-8 -*-
"""
Created on Sat Mar 31 21:16:20 2018
@author: Alvin AI
"""
import numpy as np
import matplotlib.pyplot as plt
def get_random_data():
x_1 = np.random.normal(loc=0.2,scale=0.2,size=(100,100))
x_2 = np.random.normal(loc=0.9,scale=0.1,size=(100,100))
x = np.r_[x_1,x_2]
return x
x = get_random_data()
plt.cla()
plt.figure(1)
plt.title('generated data')
plt.scatter(x[:,0],x[:,1])
plt.show()
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score#求轮廓系数
def form_clusters(x,k):
'''
Built Cluster
'''
no_clusters = k
model = KMeans(n_clusters=no_clusters,init='random')
model.fit(x)
labels = model.labels_#得到数据点的聚类标签
print labels
sh_score = silhouette_score(x,labels)
return sh_score
#k=2,3,4,5都挨个试下,然后得到其轮廓系数,用以评分
#轮廓系数的值介于-1到1之间,越接近1表明聚类效果好
sh_scores= []
for i in range(1,5):
sh_score = form_clusters(x,i+1)
sh_scores.append(sh_score)
no_clusters = [i+1 for i in range(1,5)]
plt.figure(2)
plt.plot(no_clusters,sh_scores)
plt.title('cluster quality')
plt.xlabel('no of clusters k')
plt.ylabel('sh_scores')
plt.show()
2. LVQ:Learning Vector Quantization, 学习向量量化。是黑箱方法,对于生成的原型变量很难分辨好坏,没有任何优化条件。
- 为数据集里的每个类别选择K个初始的原始向量,如果是个两分类问题,并且每个分类中有两个原型变量,那我们就需要设置4个初始的原型变量,他们是从输入的数据集中随机选取的。
- 接着进行循环,知道epsilon值变为0或者预先设定的阈值。我们得确定一个epsilon值并在每次循环中都使之减小。
- 每次循环中,我们都要采样一个输入点(带替换),采用欧式距离找出离它最近的原型向量,然后按下面的操作更新最近邻点的原型向量。
- 如果它的原型向量的类别标签和输入数据点相同,则在原型向量上增加原型向量和数据点的差异。
# -*- coding: utf-8 -*- """ Created on Sun Apr 01 11:02:16 2018 @author: Alvin AI """ from sklearn.datasets import load_iris import numpy as np from sklearn.metrics import euclidean_distances data = load_iris() x = data['data'] y = data['target'] #最大最小值缩放到[0,1],因为要进行欧式距离的计算 from sklearn.preprocessing import MinMaxScaler minmax = MinMaxScaler() x= minmax.fit_transform(x) #LVQ参数声明 R = 2 #每个类别标签有两种原型向量y n_classes = 3 #iris是有3个类别 epsilon = 0.9 #初始epsilon --> 0 epsilon_dec_factor = 0.001 #缩放因子 class prototype(object): #保存原型向量的各个细节 def __init__(self,class_id,p_vector,eplsilon): self.class_id = class_id self.p_vector = p_vector self.eplsilon = eplsilon def update(self,u_vector,increment=True): if increment: #将原型向量向输入向量靠近 self.p_vector = self.p_vector + self.eplsilon(u_vector - self.p_vector) else: #将原型向量原远离输入向量 self.p_vector = self.p_vector - self.eplsilon(u_vector - self.p_vector) #此函数用于找出离给定向量最近的原型向量 #这块代码不知道为什么有问题,好像是欧式距离那块运用的不恰当,导致distance那边逻辑判断模糊 #如果有朋友解决了这个问题请告知我一声,谢谢哈 def find_closest(in_vector,proto_vectors): closest = None closest_distance = 9999 for p_v in proto_vectors: distance = euclidean_distances(in_vector.reshape(-1,1),p_v.p_vector.reshape(-1,1)) #distance =np.linalg.norm(in_vector - p_v.p_vector) if distance < closest_distance: closest_distance = distance closest = p_v return closest #此函数用于找到最近原型向量的类别ID def find_class_id(test_vector,p_vectors): return find_closest(test_vector,p_vectors).class_id #选择初始化的k*原型向量类别数 #为每个类选择R个原型 p_vectors = [] for i in range(n_classes): y_subset = np.where(y==i)#选择一个类 x_subset= x[y_subset] samples = np.random.randint(0,len(x_subset),R)#介于0—50中间随机选择R个下标 for sample in samples: s = x_subset[sample] p = prototype(i,s,epsilon) p_vectors.append(p) while epsilon >= 0.01: #随机采样一个训练实例 rnd_i = np.random.randint(0,149) rnd_s = x[rnd_i] target_y = y[rnd_i] #为下一次循环减少epsilon epsilon = epsilon - epsilon_dec_factor #查找与给定点最相近的原型向量 closest_pvector = find_closest(rnd_s,p_vectors) #更新最相近的原型向量 if target_y == closest_pvector.class_id: closest_pvector.update(rnd_s)#靠近 else: closest_pvector.update(rnd_s,False)#远离 closest_pvector.epsilon = epsilon print 'class id \t Initial prototype vector\n' for p_v in p_vectors: print p_v.class_id,'\t',p_v.p_vector #下面为测试代码来检查方法是否正确 predicted_y = [find_class_id(instance,p_vectors) for instance in x] from sklearn.metrics import classification_report print classification_report(y,predicted_y,terget_names=['Iris-Setosa','Iris-Versicolour','Iris-Virginica'])