聚类是一种运用普遍的探索性数据分析技术,直观上讲,聚类是将对象进行分组的一项任务,使类似的对象归为一类,不类似的对象归为不一样类中。html
当聚类对象是图像的时候,就是所谓的图像聚类。git
更为详细的介绍,可参考文后的参考资料[1]。程序员
图像聚类就是在给出的图像集合中,根据图像的内容,在无先验知识的状况下,将图像按照类似度进行分类。使得分类后的图像类内类似度高,类间类似度低。中国有句俗话叫作“物以类聚,人以群分”,大概就是这个意思吧。github
前面讲到聚类是将类似度高的对象聚到一类中,如何来衡量对象之间的类似度是个关键问题。算法
按照聚类的尺度,聚类方法能够被分为如下三种:数组
下面的部分主要介绍K-means
聚类方法。bash
K-means
算法是一种基于距离的聚类算法,也叫作K均值
或K平均
,也常常被称为劳埃德(Lloyd
)算法。是经过迭代的方式将数据集中的各个点划分到距离它最近的簇内,距离指的是数据点到簇中心的距离。dom
K-means
算法的思想很简单,对于给定的样本集,按照样本之间的距离大小,将样本划分为K
个簇。将簇内的数据尽可能紧密的连在一块儿,而让簇间的距离尽可能的大。ide
Kmeans
步骤:函数
k
个簇中心坐标k
个簇中心的距离,并将数据点划分到最近的簇终止条件有:
- 再也不有从新的分配
- 达到最大迭代次数
- 全部类中心移动小于某个值
K-means
问题
贪心算法: 常常陷入局部最优解
K
的选取
对噪声或离群点比较敏感
没法区分出哪些是噪声或者离群点,只能给每一个数据点都判断出一个类别来,这样会致使样本质心偏移,致使误判或者聚类紧密程度下降。
样本点形状对聚类的影响
K-means
算法对于凸性数据具备良好的效果,可以根据聚类来将数据分为球状类的簇,但对于非凸形状的数据点就无能为力了,好比环形数据等等。以下图左边是K-means
方法的聚类效果。
聚类中心的个数K
须要事先给定。K
值的选取直接影响最终的聚类效果。
选取方法:
elbow method
经过绘制K
和损失函数的关系图,选择拐点处的K
值。即便用多个值进行尝试,取聚类指标最优或提高的转折点。K
,屡次随机初始化中心选经验上最合适的。一般是根据经验选取,由于实际操做中拐点不明显,且效率过低,实际中不容许这样作。
elbow method
也叫作“手肘法”,是利用偏差平方和(SSE)的变化趋势来做为选取K
值的指标。
其中,是第
个簇,
是
中的样本点,
是
的质心,
是全部样本的聚类偏差,表示聚类效果的好坏。
以下图所示,当K
取值为2~7时,对应的聚类结果,当K=5
时的效果最好。
K-means
选择的初始点不一样得到的最终分类结果也可能不一样。在实际使用中,咱们并不知道待聚类的数据集中哪些是咱们关注的label
,人工事先指定质心是不现实的。
通常初始质心的选择方法是:
Kmeans++
方式
K
个。距离是K-means
中衡量簇内样本点类似度的指标。
K-means
中比较经常使用的距离度量方法是:
Python
中的sklearn
库中提供了K-means
聚类的实现方法,咱们能够直接调用。
对于图像聚类来说,咱们须要提取表示图像内容的特征,
是
维的特征向量。具备
个图像,其特征向量表示为
,维度为
。
示例:
from sklearn.cluster import KMeans
import numpy as np
# X表示一组图像的特征向量
X = np.array([[1, 2], [1, 4], [1, 0],
[4, 2], [4, 4], [4, 0]])
kmeans = KMeans(n_clusters=2, random_state=0).fit(X)
kmeans.labels_
# array([0, 0, 0, 1, 1, 1], dtype=int32)
kmeans.predict([[0, 0], [4, 4]])
# array([0, 1], dtype=int32)
kmeans.cluster_centers_
# array([[ 1., 2.],
# [ 4., 2.]])
复制代码
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=1, algorithm='auto')
复制代码
参数:
参数 | 含义 |
---|---|
n_clsuters |
int , 可选,默认值为8 。聚类中心的个数,即聚类的类数 |
init |
{‘k-means++’ , 'random' 或一个ndarray},初始化质心的方法,默认是'k-means++' ,‘random’ 随机从训练数据中选初始质心,若是传递一个ndarray,应该行如(n_clusters, n_features) 并给出初始质心 |
n_init |
int ,默认10 ,用不一样质心初始化运行算法的次数,最终解是在inertia意义下选出的最优结果 |
max_iter |
int ,默认300 ,执行一次K-means 算法的最大迭代次数 |
tol |
float 型,默认0.0001 |
precompute_distances |
{auto, True, False }预先计算距离值(更快,但占用更多内存),对一组数据只运行较少次聚类结果时,不须要预选计算。 |
verbose |
int 型,默认0 ,是否打印中间过程,0是不打印 |
random_state |
int 型,RandomState 的实例或None ,可选,默认None 。若是是int ,random_state 是随机数生成器使用的种子,若是是RandomState 实例,random_state 是随机数生成器,若是是None ,随机数生成器是由np.random 的RandomState 实例 |
n_jobs |
int 型,使用的计算力的数量,经过计算并行运行的每一个n_init来实现。若是是-1 ,则全部CPU所有使用,若是指定为1 ,则不使用并行代码,方便调试。该值小于-1,则使用 (n_cpus + 1 + n_jobs) . 对于n_jobs = -2 , 使用n_cpus-1 . |
algorithm |
可选值'auto', 'full','elkan' 。'full'是传统的K-means算法,'elkan'是elkan K-means算法,默认值‘auto’会根据数据值是否稀疏,来决定如何选择'full'和'elkan'。通常,数据稠密选‘elkan’,不然就是'full'。 |
主要属性:
属性 | 含义 |
---|---|
cluster_centers_ |
向量[n_clsuters, n_features],每一个簇中心的坐标 |
Labels_ |
每一个数据的分类标签,从0开始 |
inertia_ |
float 型,每一个数据点到其簇的质心的距离之和,用来评估簇的个数是否合适 |
1. fit()
对Kmeans肯定类别之后的数据集进行聚类.
定义:
def fit(self, X, y=None)
random_state = check_random_state(self.random_state)
X = self._check_fit_data(X)
self.cluster_centers_, self.labels_, self.inertia_, self.n_iter_ = \
k_means(
X, n_clusters=self.n_clusters, init=self.init,
n_init=self.n_init, max_iter=self.max_iter, verbose=self.verbose,
precompute_distances=self.precompute_distances,
tol=self.tol, random_state=random_state, copy_x=self.copy_x,
n_jobs=self.n_jobs, algorithm=self.algorithm,
return_n_iter=True)
return self
复制代码
内部调用k_means
函数进行聚类,返回self
。
调用k_means()
函数,会返回self.cluster_centers_
,self.labels_
, self.inertia_
, self.n_iter_
。
self.cluster_centers_
:聚类中心,shape为 (k, n_features)
self.labels_
:int
,聚类索引值,shape为(n_samples,)
self.inertia_
:聚类失真值(训练集中全部观测到的距离的平方之和)self.n_iter_
:最佳结果对应的迭代次数,只有当 return_n_iter
设为True
时返回。2. predict()
根据聚类结果,肯定所属类别
def predict(self, X)
复制代码
X
:{array, sparse matrix}
,shape是[n_samples, n_features]
返回值:labels
:array
, shape是[n_samples,]
。每一个样例属于聚类的类别索引。3. fit_predict
def fit_predict(self, X, y=None)
return self.fit(X).labels_
复制代码
返回值:
labels
:array
, shape是[n_samples,]
。每一个样例属于聚类的类别索引值。计算聚类中,并预测每一个sample的聚类索引。
等效于,调用fit(X)
方法以后,调用predict(X)
函数。
注意:在此函数中,返回的是self.fit(X).labels_属性。
4. transform
def transform(self, X)
复制代码
将X转化为聚类-距离空间
返回值:
X_new
:array
, shape是[n_samples, k]
5. fit_transform
def fit_transform(self, X, y=None)
复制代码
进行聚类运算,并将X
转化到距离空间。
等效于,调用fit(X)
方法以后,调用transform(X)
函数,可是更为有效。
重要,sklearn中的Kmeans方法没法指定距离度量方法,默认使用欧式距离
K-means
默认使用的是欧式距离,这是算法设计之初的度量基础。缘由是涉及平均值的计算。
scipy
库中也实现了K-means
算法。
中心索引或聚类索引也被称为 “code” ,code到中心的映射表被称为 “code book”.
使用kmeans
函数进行聚类,须要两步来实现
kmeans
函数生成codebook
和失真值vq
函数将codebook
分配到每一个观察数据上,并获得每一个观测数据到它最近中心点的距离。示例:
import scipy
from scipy.cluster.vq import kmeans, vq, whiten
import numpy as np
#生成待聚类的数据点,这里生成了20个点,每一个点4维:
points=scipy.randn(20,4)
data=whiten(points) # 将原始数据作归一化处理
#返回聚类中心的映射表和损失
codebook, variance = kmeans(data, 4)
# 使用vq函数根据聚类中心对全部数据进行分类,vq的输出全部数据的label和距离
code, distance = vq(data, codebook)
# 结果
>>> codebook # (4,4)
array([[-1.227829 , -0.41256122, -0.1342359 , -0.98257834],
[ 1.01190005, -0.34999089, -0.13180372, 0.06394479],
[ 0.01156929, -0.39212056, 1.86893218, -0.34921357],
[ 0.21946277, 1.36809613, 0.87196001, 0.9213216 ]])
>>>variance
1.221658211170926
>>> code
array([2, 0, 0, 2, 0, 2, 1, 3, 1, 1, 3, 0, 1, 0, 1, 1, 3, 2, 3, 2],
dtype=int32)
>>>distance
array([1.32927696, 0.99594691, 1.38351644, 1.22323281, 1.12605626,
2.04444249, 0.55554746, 2.06947197, 1.44928466, 1.09481098,
1.60957745, 1.07210177, 1.3848659 , 0.6393925 , 0.69392457,
1.06200234, 1.09091552, 0.87726365, 0.76938663, 1.96214695])
复制代码
kmeans函数定义:
def kmeans(obs, k_or_guess, iter=20, thresh=1e-5, check_finite=True)
复制代码
参数:
obs
:ndarray
,MxN
数组,每行表示一个观测矢量。特征必须进过whiten
函数处理k_or_guess
:int
或者ndarray
,产生的中心点的个数,每一个中心点分配一个code
,这也是质心在生成的code_book
矩阵中的行索引,经过从观测矩阵中随机选择观测值来选择初始k中心。也能够经过传入一个kxN
的数组来指定初始k中心点。iter
:int
,可选值。运行k均值算法的次数,返回具备最低失真的code book
,若是为k_or_guess
参数的数组指定了初始质心,则将忽略此参数,此参数不表明k均值算法的迭代次数。thresh
:float
,可选值。若是自上次k均值迭代以来失真的变化小于或等于阈值,则终止k均值算法。check_finite
:bool
,可选值,默认值:True
。是否检查输入矩阵仅包含有限数。禁用可能会提升性能,可是若是输入中确实包含无穷大或NaN,则可能会致使问题(崩溃,终止)。返回:
codebook
:ndarray
,由k个质心组成的维度(k,N)
的数组distortion
:float
型,观测值与生成的中心点之间的平均欧式距离(非平方)。请注意,在K-means
算法中失真的标准定义是平方距离总和。注意: 1. `kmeans`函数中,`iter`参数用来指定运行K均值算法的次数,而不是迭代次数。算法终止条件只能经过`thresh`参数来指定。 2. 距离度量使用的是平均欧式距离(非平方)
vq函数定义:
def vq(obs, code_book, check_finite=True)
复制代码
将code book
中的每个code
分配给观察值。在MXN
的数组中的每一个观察矢量与code book
中的质心进行比较,并为其分配最接近质心的code
.
obs
中的特征应该具备单位方差,能够经过将他们传递给whiten
函数来实现。code book
可使用K-means
算法或其余编码算法来建立。
参数:
obs
:MxN
数组,每一行表明一个观测值。特征必须通过whiten
函数处理。code_book
:ndarray
。一般使用k-means算法生成,每一行表示一个不一样的code
,列表示code
的特征值。check_finite
:bool
,可选值,默认是True
。是否检查输入数组中仅包含有限值。禁用可能会提升性能,但若是输入内容确实包含无穷大或NaN,则可能会致使问题(崩溃,终止)。返回值:
code
: ndarray
,长度为M的数组,用于保存每一个观察数据的code book
。dist
: ndarray``,(M,)
每一个观察数据到它最近code的失真值。该函数也是用来实现K-means
算法。该算法尝试最小化观测值和质心之间的欧几里得距离,包括几种初始化方法。
scipy.cluster.vq.kmeans2(data, k, iter=10, thresh=1e-05, minit='random', missing='warn', check_finite=True)
复制代码
参数:
data
:ndarray
,(M,N)
的数组,包含M个具备N维的观测数据。k
:int or ndarray
,聚类个数。若是minit
参数是matrix
,或者若是给定一个ndarray
,它被解释为初始聚类,以代替使用。iter
:int
,可选值,k-means
算法运行的迭代次数,注意,与kmeans
函数的iter
参数的含义不一样。thresh
:float
,可选值,没有使用minit
:str
,可选值,初始化方法。可选择random
, points
,++
和matrix
。
random
:从高斯生成k个质心,均值和方差根据数据估算出points
:从数据中随机选择k个观测值(行)做为初始中心++
:根据kmeans++
方法选择k个观测值matrix
:将k参数解释为初始质心的(k,M)数组missing
:str
,可选值,用于解决空聚类的方法,可用方法有warn
和raise
。
warn
:给出警告并继续raise
:引起ClusterError
并终止算法check_finite
:bool
,可选值,是否检查输入矩阵仅包含有限数,默认True
返回值:
centroid
:ndarray
:一个(k,N)的数组,表示k-means
方法最后一次迭代的中心点label
:ndarray
,每一个观测值的代码或索引值。label [i]是第i个观测值最接近的质心的代码或索引示例
import scipy
from scipy.cluster.vq import kmeans2, whiten
import numpy as np
#生成待聚类的数据点,这里生成了20个点,每一个点4维:
points=scipy.randn(20,4)
data=whiten(points) # 将原始数据作归一化处理
centroid, label = kmeans2(data, 5)
# 结果
>>> centroid
array([[ 0.52132816, 0.97577703, -0.30863464, -1.30546523],
[-0.27344139, -0.81129939, -0.59560322, 0.47788319],
[ 1.99658961, -0.10701021, 1.09921144, 0.51397034],
[-0.37598454, 1.72180727, -0.18127439, 0.58114466],
[ 0.25895367, -0.01881385, 1.25681737, 0.03119893]])
>>> label
array([1, 0, 3, 0, 1, 1, 2, 4, 0, 1, 1, 0, 4, 4, 0, 3, 1, 4, 3, 2],
dtype=int32)
复制代码
[1]各种聚类(clustering)算法初探 - 郑瀚Andrew.Hann - 博客园
[2]特征提取方法:聚类之Kmeans - Jack_Kuo的博客 - CSDN博客
[3]sklearn.cluster.KMeans — scikit-learn 0.17 文档
[4]K-means clustering and vector quantization (scipy.cluster.vq) — SciPy v1.3.1 Reference Guide