K-Means聚类进行图像处理实战
在K-Means聚类算法原理中,我们对K-Means的原理做了总结,本文我们就来讨论用scikit-learn来学习K-Means聚类。重点讲述如何选择合适的k值。
1. K-Means类概述
在scikit-learn中,包括两个K-Means的算法,一个是传统的K-Means算法,对应的类是KMeans。另一个是基于采样的Mini Batch K-Means算法,对应的类是MiniBatchKMeans。一般来说,使用K-Means的算法调参是比较简单的。
用KMeans类的话,一般要注意的仅仅就是k值的选择,即参数n_clusters;如果是用MiniBatchKMeans的话,也仅仅多了需要注意调参的参数batch_size,即我们的Mini Batch的大小。
当然KMeans类和MiniBatchKMeans类可以选择的参数还有不少,但是大多不需要怎么去调参。下面我们就看看KMeans类和MiniBatchKMeans类的一些主要参数。
2. KMeans类主要参数
KMeans类的主要参数有:
1) n_clusters: 即我们的k值,一般需要多试一些值以获得较好的聚类效果。k值好坏的评估标准在下面会讲。
2)max_iter: 最大的迭代次数,一般如果是凸数据集的话可以不管这个值,如果数据集不是凸的,可能很难收敛,此时可以指定最大的迭代次数让算法可以及时退出循环。
3)n_init:用不同的初始化质心运行算法的次数。由于K-Means是结果受初始值影响的局部最优的迭代算法,因此需要多跑几次以选择一个较好的聚类效果,默认是10,一般不需要改。如果你的k值较大,则可以适当增大这个值。
4)init: 即初始值选择的方式,可以为完全随机选择’random’,优化过的’k-means++‘或者自己指定初始化的k个质心。一般建议使用默认的’k-means++’。
5)algorithm:有“auto”, “full” or “elkan”三种选择。“full"就是我们传统的K-Means算法, “elkan”是我们原理篇讲的elkan K-Means算法。默认的"auto"则会根据数据值是否是稀疏的,来决定如何选择"full"和“elkan”。一般数据是稠密的,那么就是 “elkan”,否则就是"full”。一般来说建议直接用默认的"auto"
3. MiniBatchKMeans类主要参数
MiniBatchKMeans类的主要参数比KMeans类稍多,主要有:
1) n_clusters: 即我们的k值,和KMeans类的n_clusters意义一样。
2)max_iter:最大的迭代次数, 和KMeans类的max_iter意义一样。
3)n_init:用不同的初始化质心运行算法的次数。这里和KMeans类意义稍有不同,KMeans类里的n_init是用同样的训练集数据来跑不同的初始化质心从而运行算法。而MiniBatchKMeans类的n_init则是每次用不一样的采样数据集来跑不同的初始化质心运行算法。
4)batch_size:即用来跑Mini Batch KMeans算法的采样集的大小,默认是100.如果发现数据集的类别较多或者噪音点较多,需要增加这个值以达到较好的聚类效果。
5)init: 即初始值选择的方式,和KMeans类的init意义一样。
6)init_size: 用来做质心初始值候选的样本个数,默认是batch_size的3倍,一般用默认值就可以了。
7)reassignment_ratio: 某个类别质心被重新赋值的最大次数比例,这个和max_iter一样是为了控制算法运行时间的。这个比例是占样本总数的比例,乘以样本总数就得到了每个类别质心可以重新赋值的次数。如果取值较高的话算法收敛时间可能会增加,尤其是那些暂时拥有样本数较少的质心。默认是0.01。如果数据量不是超大的话,比如1w以下,建议使用默认值。如果数据量超过1w,类别又比较多,可能需要适当减少这个比例值。具体要根据训练集来决定。
8)max_no_improvement:即连续多少个Mini Batch没有改善聚类效果的话,就停止算法, 和reassignment_ratio, max_iter一样是为了控制算法运行时间的。默认是10.一般用默认值就足够了。
4. K值的评估标准
不像监督学习的分类问题和回归问题,我们的无监督聚类没有样本输出,也就没有比较直接的聚类评估方法。但是我们可以从簇内的稠密程度和簇间的离散程度来评估聚类的效果。常见的方法有轮廓系数Silhouette Coefficient和Calinski-Harabasz Index。个人比较喜欢Calinski-Harabasz Index,这个计算简单直接,得到的Calinski-Harabasz分数值s越大则聚类效果越好。
Calinski-Harabasz分数值s的数学计算公式是:
s(k)=tr(Bk)tr(Wk)m−kk−1
其中m为训练集样本数,k为类别数。Bk为类别之间的协方差矩阵,Wk为类别内部数据的协方差矩阵。tr为矩阵的迹。
也就是说,类别内部数据的协方差越小越好,类别之间的协方差越大越好,这样的Calinski-Harabasz分数会高。在scikit-learn中, Calinski-Harabasz Index对应的方法是metrics.calinski_harabaz_score.
5. K-Means应用实例
这里我们用K-Means聚类对图像进行压缩处理
首先导入包
from PIL import Image import numpy as np from sklearn.cluster import KMeans import matplotlib import matplotlib.pyplot as plt
读取文件,由于图片的像素太多,这里随机抽取1000个样本进行训练
num_vq = 50 #设置要聚类的个数 im = Image.open('16.lena.png') # 16.son.bmp(100)/16.flower2.png(200)/16.son.png(60)/16.lena.png(50) image = np.array(im).astype(np.float) / 255 image = image[:, :, :3] # 变成3通道 image_v = image.reshape((-1, 3)) model = KMeans(num_vq) show_scatter(image_v) #自定义的画三维立体图函数 N = image_v.shape[0] # 图像像素总数 # 选择足够多的样本(如1000个),计算聚类中心 #print(N) idx = np.random.randint(0, N, size=1000) image_sample = image_v[idx] #print(image_sample) model.fit(image_sample) c = model.predict(image_v) # 聚类结果 print( '聚类结果:\n', c) print ('聚类中心:\n', model.cluster_centers_)
画图,这里的restore_image函数是自定义的将聚类后的结果组合成图片显示
plt.figure(figsize=(15, 8), facecolor='w') plt.subplot(121) plt.axis('off') plt.title(u'原始图片', fontsize=18) plt.imshow(image) # plt.savefig('1.png') plt.subplot(122) vq_image = restore_image(model.cluster_centers_, c, image.shape) # 恢复图像 plt.axis('off') plt.title(u'矢量量化后图片:%d色' % num_vq, fontsize=18) plt.imshow(vq_image) # plt.savefig('2.png') plt.tight_layout(1.2) plt.show() def restore_image(cb, cluster, shape): row, col, dummy = shape image = np.empty((row, col, 3)) index = 0 for r in range(row): for c in range(col): image[r, c] = cb[cluster[index]] index += 1 return image def show_scatter(a): N = 10 print( '原始数据:\n', a) density, edges = np.histogramdd(a, bins=[N,N,N], range=[(0,1), (0,1), (0,1)]) density /= density.max() x = y = z = np.arange(N) d = np.meshgrid(x, y, z) fig = plt.figure(1, facecolor='w') ax = fig.add_subplot(111, projection='3d') ax.scatter(d[1], d[0], d[2], c='r', s=100*density, marker='o', depthshade=True) ax.set_xlabel(u'红色分量') ax.set_ylabel(u'绿色分量') ax.set_zlabel(u'蓝色分量') plt.title(u'图像颜色三维频数分布', fontsize=20) plt.figure(2, facecolor='w') den = density[density > 0] den = np.sort(den)[::-1] t = np.arange(len(den)) plt.plot(t, den, 'r-', t, den, 'go', lw=2) plt.title(u'图像颜色频数分布', fontsize=18) plt.grid(True) plt.show()
阅读更多
- OpenCV3.0 Examples学习笔记(13)-kmeans.cpp-kmeans函数实现对图像位置进行聚类
- opengl对图像进行模糊处理
- 基于K-means聚类的图像分割
- 在Android平台上利用opencv进行图像处理之边缘检测、灰度变换、缩小
- 使用 Java 进行图像处理 - 取得图像上指定位置像素的 rgb 颜色分量
- 用matlab对图像进行平滑处理
- 高光谱图像处理ENVI实战使用教程一
- OpenGL使用OpenCV处理图像进行纹理映射的使用范例
- 用C++ Builder对图像进行特殊效果处理
- MATLAB图像处理_直接操作像素点进行颜色变换
- QT进行图像处理-灰度直方图
- 用MATLAB对图像进行量化处理
- 推荐使用scikits.image 进行图像处理, 比较好用.
- 使用Matlab进行图像处理
- 基于K-means聚类的图像分割
- 【OpenCV学习】Kmean均值聚类对图片进行减色处理
- 使用CNN kernel对图像进行【锐化、模糊、浮雕等】处理
- 使用 Java 进行图像处理 - 将彩色图像转换为灰度图
- 用Python进行图像处理
- 在 NASA 使用开源工具进行图像处理