K-Means算法是最基本的一种聚类算法,也会有一些问题,前面的博客《机器学习(聚类二)——K-Means》中有介绍,这里就不详细说了。下面介绍一下典型的优化算法:
1)K-Mediods聚类(K中值聚类)
K-means算法在迭代的过程中使用所有点的均值作为新的质点(中心点),如果簇中存在异常点,将导致均值偏差比较严重。比如一个簇中有2、4、6、8、100五个数据,那么新的质点为24,显然这个质点离绝大多数点都比较远;在当前情况下,使用中位数6可能比使用均值的想法更好,使用中位数的聚类方式叫做 K-Mediods聚类(K中值聚类)
2)二分K-Means算法
解决K-Means算法对初始簇心比较敏感的问题,二分K-Means算法是一种弱化初始质心的一种算法,具体思路步骤如下:
从队列中选择划分聚簇的规则一般有两种方式;分别如下:
3)K-Means++
解决K-Means算法对初始簇心比较敏感的问题,K-Means++算法和K-Means算法的区别主要在于初始的K个中心点的选择方面,K-Means算法使用随机给定的方式,K-Means++算法采用下列步骤给定K个初始质点:
缺点:由于聚类中心点选择过程中的内在有序性,在扩展方面存在着性能方面的问题(第k个聚类中心点的选择依赖前k-1个聚类中心点的值)
4)K-Means||
解决K-Means++算法缺点而产生的一种算法。
主要思路是改变每次遍历时候的取样规则,并非按照K-Means++算法每次遍历只获取一个样本,而是每次获取K个样本,重复该取样操作O(logn)次,然后再将这些抽样出来的样本聚类出K个点,最后使用这K个点作为K-Means算法的初始聚簇中心点。实践证明:一般5次重复采用就可以保证一个比较好的聚簇中心点。
样本稀疏了,质点变化会更剧烈。效率也会更高。
5)Canopy算法
Canopy算法属于一种“粗”聚类算法,执行速度较快,但精度较低,算法执行步骤如下:
Canopy算法过程图形说明
Canopy算法得到的最终结果的值,聚簇之间是可能存在重叠的,但是不会存在某个对象不属于任何聚簇的情况。
由于K-Means算法存在初始聚簇中心点敏感的问题,常用使用Canopy 和 K-Means算法混合形式进行模型构建
优点:
注:目前的sklearn中没有相应的API
6)Mini Batch K-Means算法(与k-means||类似)
Mini Batch K-Means算法是K-Means算法的一种优化变种,采用小规模的数据子集(每次训练使用的数据集是在训练算法的时候随机抽取的数据子集)减少计算时间,同时试图优化目标函数;Mini Batch K-Means算法可以减少K-Means算法的收敛时间,而且产生的结果效果只是略差于标准K-Means算法。(可以说二者唯一的区别就是采样:全部和部分)
算法步骤如下:
总 :这里提到了6种算法:
这里只实现K-Means和Mini Batch K-Means算法比较案例。基于scikit包中的创建模拟数据的API创建聚类数据,使用K-means算法和MiniBatch K-Means算法对数据进行分类操作,比较这两种算法的聚类效果以及聚类的消耗时间长度。
API
class sklearn.cluster.KMeans(n_clusters=8, init=‘k-means++’, n_init=10, max_iter=300, tol=0.0001, precompute_distances=‘auto’, verbose=0, random_state=None, copy_x=True, n_jobs=None, algorithm=‘auto’)[source]
class sklearn.cluster.MiniBatchKMeans(n_clusters=8, init=‘k-means++’, max_iter=100, batch_size=100, verbose=0, compute_labels=True, random_state=None, tol=0.0, max_no_improvement=10, init_size=None, n_init=3, reassignment_ratio=0.01)[source]
参数,基本同kmeans
代码
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from sklearn.cluster import MiniBatchKMeans, KMeans
from sklearn.metrics.pairwise import pairwise_distances_argmin
from sklearn.datasets.samples_generator import make_blobs
## 设置属性防止中文乱码
mpl.rcParams['font.sans-serif'] = [u'SimHei']
mpl.rcParams['axes.unicode_minus'] = False
#初始化三个中心
centers = [[1, 1], [-1, -1], [1, -1]]
clusters = len(centers) #聚类的数目为3
#产生3000组二维的数据,中心是意思三个中心点,标准差是.7
X, Y = make_blobs(n_samples=3000, centers=centers, cluster_std=0.7, random_state=28)
#构建kmeans算法
k_means = KMeans(init='k-means++', n_clusters=clusters, random_state=28)
t0 = time.time() #当前时间
k_means.fit(X) #训练模型
km_batch = time.time() - t0 #使用kmeans训练数据的消耗时间
print ("K-Means算法模型训练消耗时间:%.4fs" % km_batch)
K-Means算法模型训练消耗时间:0.0811s
构建MiniBatchKMeans算法
batch_size = 100
mbk = MiniBatchKMeans(init='k-means++', n_clusters=clusters, batch_size=batch_size, random_state=28)
t0 = time.time()
mbk.fit(X)
mbk_batch = time.time() - t0
print ("Mini Batch K-Means算法模型训练消耗时间:%.4fs" % mbk_batch)
Mini Batch K-Means算法模型训练消耗时间:0.0560s
Mini Batch K-Means算法要更快一些。
#预测结果
km_y_hat = k_means.predict(X)
mbkm_y_hat = mbk.predict(X)
print(km_y_hat[:10])
print(mbkm_y_hat[:10])
print(k_means.cluster_centers_)
print(mbk.cluster_centers_)
[0 2 2 2 2 1 0 0 2 2]
[1 0 0 0 0 2 1 1 0 0]
[[-1.0600799 -1.05662982]
[ 1.02975208 -1.07435837]
[ 1.01491055 1.02216649]]
[[ 0.99602094 1.10688195]
[-1.00828286 -1.05983915]
[ 1.07892315 -0.94286826]]
##获取聚类中心点并聚类中心点进行排序
k_means_cluster_centers = k_means.cluster_centers_#输出kmeans聚类中心点
mbk_means_cluster_centers = mbk.cluster_centers_#输出mbk聚类中心点
print ("K-Means算法聚类中心点:\ncenter=", k_means_cluster_centers)
print ("Mini Batch K-Means算法聚类中心点:\ncenter=", mbk_means_cluster_centers)
order = pairwise_distances_argmin(k_means_cluster_centers,
mbk_means_cluster_centers)
#方便后面画图
order
K-Means算法聚类中心点:
center= [[-1.0600799 -1.05662982]
[ 1.02975208 -1.07435837]
[ 1.01491055 1.02216649]]
Mini Batch K-Means算法聚类中心点:
center= [[ 0.99602094 1.10688195]
[-1.00828286 -1.05983915]
[ 1.07892315 -0.94286826]]
array([1, 2, 0], dtype=int64)
## 画图
plt.figure(figsize=(12, 6), facecolor='w')
plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.9)
cm = mpl.colors.ListedColormap(['#FFC2CC', '#C2FFCC', '#CCC2FF'])
cm2 = mpl.colors.ListedColormap(['#FF0000', '#00FF00', '#0000FF'])
#子图1:原始数据
plt.subplot(221)
plt.scatter(X[:, 0], X[:, 1], c=Y, s=6, cmap=cm, edgecolors='none')
plt.title(u'原始数据分布图')
plt.xticks(())
plt.yticks(())
plt.grid(True)
#子图2:K-Means算法聚类结果图
plt.subplot(222)
plt.scatter(X[:,0], X[:,1], c=km_y_hat, s=6, cmap=cm,edgecolors='none')
plt.scatter(k_means_cluster_centers[:,0], k_means_cluster_centers[:,1],c=range(clusters),s=60,cmap=cm2,edgecolors='none')
plt.title(u'K-Means算法聚类结果图')
plt.xticks(())
plt.yticks(())
plt.text(-3.8, 3, 'train time: %.2fms' % (km_batch*1000))
plt.grid(True)
#子图三Mini Batch K-Means算法聚类结果图
plt.subplot(223)
plt.scatter(X[:,0], X[:,1], c=mbkm_y_hat, s=6, cmap=cm,edgecolors='none')
plt.scatter(mbk_means_cluster_centers[:,0], mbk_means_cluster_centers[:,1],c=range(clusters),s=60,cmap=cm2,edgecolors='none')
plt.title(u'Mini Batch K-Means算法聚类结果图')
plt.xticks(())
plt.yticks(())
plt.text(-3.8, 3, 'train time: %.2fms' % (mbk_batch*1000))
plt.grid(True)
#
different = list(map(lambda x: (x!=0) & (x!=1) & (x!=2), mbkm_y_hat))
for k in range(clusters):
different += ((km_y_hat == k) != (mbkm_y_hat == order[k]))
identic = np.logical_not(different)
different_nodes = len(list(filter(lambda x:x, different)))
plt.subplot(224)
# 两者预测相同的
plt.plot(X[identic, 0], X[identic, 1], 'w', markerfacecolor='#bbbbbb', marker='.')
# 两者预测不相同的
plt.plot(X[different, 0], X[different, 1], 'w', markerfacecolor='m', marker='.')
plt.title(u'Mini Batch K-Means和K-Means算法预测结果不同的点')
plt.xticks(())
plt.yticks(())
plt.text(-3.8, 2, 'different nodes: %d' % (different_nodes))
plt.show()