接着机器学习系列文章的脚印,今天介绍一下机器学习的无监督算法--聚类, 内容主要包括以下几个部分:
(1)常见的聚类方法的方法的通俗讲解和图片演示
(2) 上述算法的数学公式简单展示和推导理解
(3) 常见聚类算法的sklearn 的简单用法demo
(4) 官方实例的 一个实际操作
一、常见聚类方法/公式展示和简单推导
- k-means(k均值聚类)
- 基于密度的DBSCAN算法
- 用高斯混合模型(GMM)的最大期望(EM)聚类
- 凝聚层次聚类
- k-means(k均值聚类)
(1) 初始化K个质心,质心个数的选择需要自己根据数据量定夺
(2) 计算每一个数据点到k 个质心的距离,随即选择最短的距离,并将该点归为此质心
(3)计算每一类中中心点作为新的中心点
(4)重复以上步骤,直到每一类中心在每次迭代后变化不大为止。同时,也可以多次随机初始化中心点,然后选择运行结果最好的一个。
优点:便捷性
不足:最好可以之前预设好质心的个数,也就是簇的个数
数学原理:本质上就是利用了欧式距离
周志华西瓜书上关于k-means算法讲解

2.基于密度的DBSCAN算法
特点:
(1) 聚类的时候不要确定质心(簇) 的个数
(2) 最终的簇的个数也并不确定
一些属性词的普适化解释
- 核心点:以该点为圆心,EPS半径内的点的个数满足大于等于minpoints ,那么该点就是核心点
- 边界点:以该点为圆心,EPS半径内的点的个数小于minpoints, 且,该点在上述核心点的EPS参数密度(就是上述核心点的圆圈里)里,这些点就是边界点 --下图黄色的点
- 噪音点,既不是核心点,也不是边界点
*ϵ-邻域:即对于样本点xi,和它的距离在ϵ之内的属于样本集D中的点的集合,
即Nϵ(xj)={si∈D|dist(xi,xj)≤ϵ}
*密度直达和密度可达:密度直达,假设核心点xi,在它的ϵ-邻域中存在xj,则xi和xj就是密度直达,同时,如果存在一个点集,n1,n2,n3,......nN,xi和其中的某一个点是密度直达,其中某一个点到xj是密度直达,那么就说xi 到xj 是密度可达
*密度相连:对于样本点xj和xi若存在点xk使得xj和xi均可由xk密度可达,则称xj和xi密度相连,其实本质上是密度可达的双向性


最终的聚类结果展示和说明

如图算法自动将数据集分成了3簇,用三种颜色代表。每一簇内较大的点代表核心对象,较小的点代表边界点。黑色的点代表离群点或者叫噪声点。
优点:
(1)不需要指定cluster的数目
(2) 参数较少,只有两个
(3)不受数据集点的分布形状限制,这样避免了k-means算法带来的分类误差

(4)可以识别出噪音,且对噪音并不敏感
缺点:
(1)DBSCAN的聚类效果收到距离公式的选择,一般会选择采用欧式距离,对于高纬度的数据,会有”维度灾难“
(2)该方法不适合于密度差异很大的数据集,这样会导致半径和minpoints的选择较为困难
周志华西瓜书算法讲解

上述算法的理解难点是""和Ck的理解,其中,前一个符号的含义是取两者的差集,后者本质上就是取的交集作为一个簇
3.用高斯混合模型(GMM)的最大期望(EM)聚类
这个算法比较难以理解,在进行该算法之前,需要理解预备知识
数学期望(离散)
设离散型随机变量X的分布为
![]()
那么其数学期望为![]()
数学期望(连续型)
![]()
随机变量的方差
![]()
标准差为其二次方根
正态分布
![]()
概率密度函数
其中
即为协方差
协方差
![]()
多维高斯分布对应的概率密度函数
![]()
高斯混合分布,其实本质上是多维的高斯分布,其中结合了朴素贝叶斯,极大似然法等。首选我们要了解聚类的目的就是将数据分到其本该归属的族内
在周志华的书中对于高斯分布做了如下的解释和定义
![]()
![]()
看到上述高斯混合分布的公式,是不是感觉到很难理解,α“混合系数”到底代表的是什么?另外,高斯混合分布怎么和朴素贝叶斯联系到一起的呢?
我们先来回答第二个问题,我们聚类的目的就是要知道数据属于哪一簇,也就是zj的下标是?

上式子中的分母是不是跟高斯混合分布一模一样,这里αl就是高斯混合分布中的混合系数,那么回答第一个问题,混合系数有没有比较直观的理解方式呢?接下来我们来看一下全概率公式
P(B)=P(A1)P(B|A1)+ P(A2)P(B|A2)+…+ P(An)P(B|An)
如果将A1,2,3,......n理解为多个簇,也就是多个高斯分布,是不是上述的分母和混合系数就可以理解了?对!混合系数就是每一个簇(高斯分布)出现的概率
那我们怎么才能确定数据属于哪一个zj?也就是哪一个高斯成分呢?当然就是要求出上述的最大值,即上述9.30的最大值。我们想到用极大似然法

关于极大似然估计的通俗详细理解,请看该位博主的文章,传送门:
https://blog.csdn.net/zengxiantao1994/article/details/72787849
为什么要选择使用EM算法?(Expectation-maximization algorithm,又译期望最大化算法),我个人的理解是,把xj看作是一组要进行分类(这里是找到对应的高斯分布),那么它直接对应的是zj(某一个高斯分布),而并非直接对应到该zj的参数,这有点像复合函数,复合函数的求导,也是由内到外,一层一层的求偏导
那我们就加入zj,来变EM算法,在此之前,还需要了解到
-
jensen 不等式
回顾优化理论中的一些概念。设f是定义域为实数的函数,如果对于所有的实数x,



,那么称f是严格凸函数。
如果f是凸函数,X是随机变量,那么


知道了上述的不等式后,我们来看极大似然法的EM求解

从(2)到(3)式是由上述的jensen不等式得到的,



周志华书中的伪代码:

4.层次聚类
(1)示意图:

(2)基本思想
1.初始化–>把每个样本归为一类,计算每两个类之间的距离,也就是样本与样本之间的相似度;
2.寻找各个类之间最近的两个类,把他们归为一类(这样类的总数就少了一个);
3.重新计算新生成的这个类与各个旧类之间的相似度;
4.重复2和3直到所有样本点都归为一类,结束。
(3)周志华书的伪代码

(4)优缺点:
优点:
不需要知道有多少个簇
对于距离度量标准的选择并不敏感
缺点:
效率低
二、skelarn 简单介绍demo
这一part 主要介绍常用的聚类方法k-means 和 DBSCAN 其他聚类算法大家感兴趣可以看官方文档,毕竟精力有限,不在此进行总结
传送门:https://blog.csdn.net/chinachenyyx/article/details/75299043
- kmeans 聚类
"""
sklearn 官方文档
"""
"""
1.首先是k-means聚类
(1)相关的参数
n_clusters 初始化质心的个数,默认为8
init 设定选择质心的方法,可接受三种,k-means++,random,ndarray
第一种官方解释为最快
第二种为随机选取observations(统计学中的体量,其实就是数据量),或者rows
第三种为数组形式,若为数组需要给出shape
n_init 每次会选取k个质心进行训练,默认为10 代表,会选择10次,每次会初始化不同的k个质心
max_iter 最大迭代次数 tol 容忍度,即可以接受的最大误差值,是停止迭代的标志 默认为1e-4
precompute distances 是否需要提前计算距离,这个参数会在空间和时间之间做权衡,如果是True 会把整个距离矩阵都放到内存中,
auto 会默认在数据样本大于featurs*samples 的数量大于12e6 的时候False,False 时核心实现的方法是利用Cpython 来实现的
verbose 冗长模式,可以忽略。 random_state 整型 不太理解
copy_x 是否修改数据的一个标记,如果True,即复制了就不会修改数据
algorithm k-means 的实现算法, 可接受三种,auto,full,elkan, 其中full 表示EM 算法
(2)相关属性
cluster_centers_ 质心的coordinates(坐标)
labels_ 每一个点的标签属性
inertia_ 所有的样本到其最近的cluster_center 的距离之和
n_iter_ 从开始到结束迭代运行的次数
"""
from sklearn.cluster import KMeans
import numpy as np
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)
#print (kmeans.labels_)#返回的是[0,0,0,1,1]
y=[[0,0],[4,4]]
#print (kmeans.fit_predict(y))#返回的是对应样本所属簇心的索引值,也就是labels 的索引值,因此返回的是[0,1]
#print (kmeans.predict(y))#返回的是样本所属的质心,因此返回为[0,0],注意和上述的fit_predict进行对比
#print (kmeans.get_params()) 以字典的形式返回所有的参数名称以及对应的值
#print (kmeans.fit_transform(y)) 我的理解是计算样本到对应簇心的距离,随后按照质心的维度进行拆解,返回的是矩阵,该例子返回的是2*2的矩阵
#print (kmeans.transform(y)) transform x to a cluster-distince space 转置
#print (kmeans.score(y)) Opposite of the value of X on the K-means objective.
#下面是官方的demo
#传送门:https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_assumptions.html
"""
文档对于该实例的展示用途如下:
这个例子是为了说明k-means会产生不直观的、可能是意料之外的集群的情况。
在前三个图中,输入数据不符合k-means make的一些隐含假设,因此产生了不希望出现的集群。
最后一个图中,k-means返回直观的集群,尽管大小不均匀
"""
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs#对于该数据集合重要的参数就是n_samples 数据集个数,n_features 属性的个数,centers 簇的个数,random_state 随机初始化质心数量
plt.figure(figsize=(12,12))
n_samples=1500
random_state=170
x,y=make_blobs(n_samples=n_samples,random_state=random_state)#x为样本集合,y为对应的标签集合
#print(x)
"""
# Incorrect numberr of cluster
y_pred=KMeans(n_clusters=2,random_state=random_state).fit_predict(x)
print (y_pred)
plt.subplot(221) #1代表图形显示的位置索引,产生4张图再一块画布上,显示的位置为1,后边三张图一次为2,3,4
plt.scatter(x[:,0],x[:,1],c=y_pred)
plt.title ('Incorrect Number of Blobs')
plt.show()
该图的错误性在于初始质心选择不当所致,应该至少为3个
"""
"""
# Anisotropicly distributed data
transformation = [[0.60834549, -0.63667341], [-0.40887718, 0.85253229]]
x_aniso = np.dot(x, transformation)
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(x_aniso)
plt.subplot(222)
plt.scatter(x_aniso[:, 0], x_aniso[:, 1], c=y_pred)
plt.title("Anisotropicly Distributed Blobs")
plt.show()
该示例聚类失败的原因是异方性,我的个人理解就是数据的离散性不够
"""
"""
x_varied,y_varied=make_blobs(n_samples=n_samples,cluster_std=[1.0,2.5,0.5],random_state= random_state,n_features=2)
#cluster_std:每个簇的标准差,衡量某簇数据点的分散程度(见效果图) float or sequence of floats, optional (default=1.0)
y_pred = KMeans(n_clusters=3, random_state=random_state).fit_predict(x_varied)
plt.subplot(223)
plt.scatter(x_varied[:, 0], x_varied[:, 1], c=y_pred)
plt.title("Unequal Variance")
plt.show()
该示例失败的原因是,每一个簇心覆盖的点的离散程度是不同的,有的簇覆盖的数据分散性大,有的分散性较小
"""
"""
import numpy as np
array1=np.array([[1,2,3],[4,5,6]])#2*3
array2=np.array([[7,8,9],[10,11,12]])#2*3
#print (np.stack(a,1))列变为行
[[1 4]
[2 5]
[3 6]]
arr1 = np.array([[1,2,3],[4,5,6]])
arr2 = np.array([[7,8,9],[10,11,12]])
res = np.vstack((arr1, arr2))
print (res)
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
arr11 = np.array([[1, 2], [3, 4], [5, 6]])
arr22 = np.array([[7, 8], [9, 0], [0, 1]])
res_cop = np.hstack((arr1, arr2))
print (res_cop)
[[ 1 2 3 7 8 9]
[ 4 5 6 10 11 12]]
"""
"""
# Unevenly sized blobs
x_filtered = np.vstack((x[y == 0][:500], x[y == 1][:100], x[y == 2][:10]))
y_pred = KMeans(n_clusters=3,random_state=random_state).fit_predict(x_filtered)
plt.subplot(224)
plt.scatter(x_filtered[:, 0], x_filtered[:, 1], c=y_pred)
plt.title("Unevenly Sized Blobs")
plt.show()
该方法的结果大致可以接受,但唯一的不足就是每一簇的数据个数不太均匀,有些多,有些少
"""
2.DBSCAN 聚类
#下面是DBSCN聚类
"""
2.DBSCAN聚类
(1) 相关参数
传送门:https://scikit-learn.org/0.15/modules/generated/sklearn.cluster.DBSCAN.html
看了文章上述对于DBSCAN的解释,会对其参数了解起到一定作用
eps: 说白了就是核心点对应的ϵ-邻域的半径,因此eps过大,则更多的点会落在核心对象的ϵ-邻域,此时我们的类别数可能会减少,
本来不应该是一类的样本也会被划为一类。反之则类别数可能会增大,本来是一类的样本却被划分开。
min_samples:就是文章上述所说的minpoints,默认为5
metric: 点距离的计算方法,常用的是欧式距离(euclidean),曼哈顿距离(manhattan)
random_state: 初始化质心,跟上述k-means的参数一样
(2)相关使用方法,属性这块感觉没什么用,有兴趣的同学可以自己根据上边传送门学习
fit(X) 训练样本集
fit_predict(X) 预测样本集,Performs clustering on X and returns cluster labels.
get_params() get parameters for this estimator
"""
#下面是官方给出的demo 和自己的理解注释
import numpy as np
from sklearn.cluster import DBSCAN
from sklearn.datasets.samples_generator import make_blobs#自带数据库
from sklearn.preprocessing import StandardScaler#对原始的数据进行预处理,使得离散程度减弱,更加复合高斯分布\
import matplotlib.pyplot as plt
"""
对应的参数为
parameters:
with_mean boolean 为真的时候,表明center the data before scaling 就是先平均再规范化
with_std:boolean If True, scale the data to unit variance (or equivalently, unit standard deviation).
意思是为真的时候计算方差和标准差
"""
centers = [[1, 1], [-1, -1], [1, -1]]
x, labels_true = make_blobs(n_samples=750, centers=centers, cluster_std=0.4,random_state=0)
#print (x)
#print (labels_true)0,1,2 组成的1维数据标签
x=StandardScaler().fit_transform(x)#该步骤的主要作用就是样本集的预处理,这里要强调transform()和fit_transform()的区别
"""
通俗解释传送门:https://blog.csdn.net/quiet_girl/article/details/72517053
"""
###########
#compute DBSCAN
db=DBSCAN(eps=0.3, min_samples=10).fit(x)
#print (db.labels_) labels_属性返回每一个样本划分的标签
#print (db.core_sample_indices_) #返回每个样本索引,该例子就是0-749
core_samples_mask = np.zeros_like(db.labels_,dtype=bool)#np.zeros_like 返回参数同shape的0组成的数组,该例子返回bool型,因此返回的都为False
#print (core_samples_mask)
core_samples_mask[db.core_sample_indices_] = True
#print (core_samples_mask)
labels = db.labels_
#print (labels)
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)#4-1
#print (n_clusters_)
unique_labels=set(labels)
colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_labels)))
"""
对于上述的理解给出几个例子
>>> np.linspace(2.0, 3.0, num=5)
array([ 2. , 2.25, 2.5 , 2.75, 3. ])
>>> np.linspace(2.0, 3.0, num=5, endpoint=False)
array([ 2. , 2.2, 2.4, 2.6, 2.8])
>>> np.linspace(2.0, 3.0, num=5, retstep=True)
(array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
colors = plt.cm.Spectral(np.arange(5)) 产生5种不同颜色
"""
for k,col in zip(unique_labels,colors):
if k==-1:
# black used for noise
col='k'
class_member_mask=(labels==k)
xy = x[class_member_mask & core_samples_mask] #通过 &,|来进行一个样本的分类
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
markeredgecolor='k', markersize=14)
xy = x[class_member_mask & ~core_samples_mask]
plt.plot(xy[:, 0], xy[:, 1], 'o', markerfacecolor=col,
markeredgecolor='k', markersize=6)
plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()
关于机器学习聚类的总结接近尾声了,下一篇是机器学习系列的最后一种常见算法PCA,之后该机器学习--sklearn就结束了,下一系列承接这一系列进行github/kaggle 上面的实操练习,同时搭配github上目前流行的 机器学习100天(大家感兴趣可以先行学习,非常好的资源,传送门:https://github.com/Avik-Jain/100-Days-Of-ML-Code, 什么?看英文头晕,最近偶然发现了授权中文翻译版!!良心资源,https://github.com/Avik-Jain/100-Days-Of-ML-Code/blob/master/Code/Day%201_Data%20PreProcessing.md)
网友评论