6. 聚类算法之K-Means

对着背影说爱祢 提交于 2020-01-01 16:10:19

有监督学习&无监督学习:

决策树,随机森林,PCA和逻辑回归,他们虽然有着不同的功能,但却都属于“有监督学习”的一部分,即是说,模型在训练的时候,即需要特征矩阵X,也需要真实标签y。

机器学习当中,还有相当一部分算法属于“无监督学习”,无监督的算法在训练的时候只需要特征矩阵X,不需要标签。而聚类算法,就是无监督学习的代表算法。

 

K-Means的定义:

作为聚类算法的典型代表,KMeans可以说是最简单的聚类算法没有之一,那它是怎么完成聚类的呢?

答:

KMeans算法将一组N个样本的特征矩阵X划分为K个无交集的簇,直观上来看是簇是一组一组聚集在一起的数据,在一个簇中的数据就认为是同一类。簇就是聚类的结果表现。

簇中所有数据的均值通常被称为这个簇的“质心”(centroids)。
在一个二维平面中,一簇数据点的质心的横坐标就是这一簇数据点的横坐标的均值,质心的纵坐标就是这一簇数据点的纵坐标的均值。同理可推广至高维空间。

簇的个数K是一个超参数,需要我们人为输入来确定。KMeans的核心任务就是根据我们设定好的K,找出K个最优的质心,并将离这些质心最近的数据分别分配到这些质心代表的簇中去。

K-Means的过程:

1 随机抽取K个样本作为最初的质心
2 开始循环:
    2.1 将每个样本点分配到离他们最近的质心,生成K个簇
    2.2 对于每个簇,计算所有被分到该簇的样本点的平均值作为新的质心
3 当质心的位置不再发生变化,迭代停止,聚类完成

评估指标:

被分在同一个簇中的数据是有相似性的,而不同簇中的数据是不同的,当聚类完毕之后,我们就要分别去研究每个簇中的样本都有什么样的性质,从而根据业务需求制定不同的商业或者科技策略。

簇内平方和(cluster Sum of Square), 又叫做Inertia。
而将一个数据集中的所有簇的簇内平方和相加,就得到了整体平方和(Total Cluster Sum of Square),又叫做total inertia。

Total Inertia越小,代表着每个簇内样本越相似,聚类的效果就越好。
因此,KMeans追求的是,求解能够让Inertia最小化的质心。

实际上,在质心不断变化不断迭代的过程中,总体平方和是越来越小的。我们可以使用数学来证明,当整体平方和最小的时候,质心就不再发生变化了。

如此,K-Means的求解过程,就变成了一个最优化问题。

轮廓系数也可以。

 

聚类的实例:

# 计算机生成的数据集:sklearn.datasets.make_<name>
# blobs 一点 一小片

# 自己创建数据集 
# make_blobs会根据用户指定的样本个数、特征数量、中心点数量、范围等
# n_features<=3 才能被可视化
# 来生成几类数据,这些数据可用于测试聚类算法的效果




from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

x,y=make_blobs(n_samples=500,n_features=2,
               centers=4,random_state=1)


fig,ax1=plt.subplots(1)

# fig一个画布,ax1一个子图。subplot(1)一个子图,这段代码相当于:
# fig=plt.figure()
# ax1=fig.subplots(1)

ax1.scatter(x[:,0],x[:,1],marker='o',s=8)

#   x的所有行和第0列为横坐标,x的所有行和第一列为纵坐标
#   marker点的形状 s点的大小
plt.show()

基于这个分布,我们来使用Kmeans进行聚类。

假设在不知道上面的数据是几簇的条件下,确定分几簇好?

(真实答案在文章末尾,但实际生活中的聚类往往是没有答案的,只有通过聚多类找相对好的或者适合业务的。)

 

首先,我们要猜测一下,这个数据中有几簇?

若分三簇:

from sklearn.cluster import KMeans
n_clusters=3

# 实例化
cluster=KMeans(n_clusters=n_clusters,random_state=0).fit(x)
# 重要属性labels_,用来查看聚好的类别,每个样本对应的类

y_pred=cluster.labels_
y_pred

# KMeans因为不需要建立模型或者预测结果,因此我们只需要fit就能得到聚类的结果了。
# 但是KMeans也有接口predict和fit_predict,表示学习数据x并对x的类进行预测
# 但是fit_predict所得到的结果和直接调用labels_的结果一模一样。

pre=cluster.fit_predict(x)
pre
# 重要属性cluster_centers_,用来查看质心(横坐标,纵坐标) 
# 因为聚了3类,所以这里有3个坐标

centroid=cluster.cluster_centers_
centroid
# 分三簇时聚类的图形

color=["red","pink","orange"]
fig,ax1=plt.subplots(1)

for i in range(n_clusters):
    ax1.scatter(x[y_pred==i,0],x[y_pred==i,1],marker='o',s=8,c=color[i])

ax1.scatter(centroid[:,0],centroid[:,1],marker="x",s=100,c="black")

plt.show()

 

# 重要属性inertia_,查看总距离平方和
# 聚类效果越好,inertia越低

# 分3簇时的总距离平方和:
inertia=cluster.inertia_
inertia

1903.4503741659223
# 重要属性轮廓系数silhouette_score,
# 分3簇时的轮廓系数:

from sklearn.metrics import silhouette_score
silhouette_score(x,cluster.labels_)

0.5882004012129721

# 每个样本点的轮廓系数:
from sklearn.metrics import silhouette_samples
silhouette_samples(x,cluster.labels_)

分好多簇时的总距离平方和inertia和轮廓系数silhouette_score:

# 分2,3,4,5,6,7,8簇时的总距离平方和inertia
# 和轮廓系数silhouette_score:

# 聚类效果越好,inertia越低
# 聚类效果越好,silhouette_score越接近1

sc=[]
inertia=[]

for i in range(2,9):
    cluster= KMeans(n_clusters=i,random_state=0).fit(x)
    
    s_=silhouette_score(x,cluster.labels_)
    sc.append(s_)
    
    inertia_=cluster.inertia_
    inertia.append(inertia_)
    

可见,随着分的簇越多,inertia越小,这说明inertia并不能作为衡量KMeans的标准,有很多缺点:

首先,它不是有界的。我们只知道,Inertia是越小越好,是0最好,但我们不知道,一个较小的Inertia究竟有没有达到模型的极限,能否继续提高。

第二,它的计算太容易受到特征数目的影响,数据维度很大的时候,Inertia的计算量会陷入维度诅咒之中,计算量会爆炸,不适合用来一次次评估模型。

第三,Inertia对数据的分布有假设,它假设数据满足凸分布(即数据在二维平面图像上看起来是一个凸函数的样 子),并且它假设数据是各向同性的(isotropic),即是说数据的属性在不同方向上代表着相同的含义。但是现实 中的数据往往不是这样。所以使用Inertia作为评估指标,会让聚类算法在一些细长簇,环形簇,或者不规则形状的流形时表现不佳。

那用什么指标好呢?

答:

轮廓系数silhoutte_score

轮廓系数范围是(-1,1),其中值越接近1表示样本与自己所在的簇中的样本很相似,并且与其他簇中的样本不相似;
当样本点与簇外的样本更相似的时候,轮廓系数就为负;
当轮廓系数为0时,则代表两个簇中的样本相似度一致,两个簇本应该是一个簇。

 

 

谜底:

# 画出生成的图真实的样子。因为我一开始就分了4个feature。

color=['red','pink','orange','gray']
fig,ax1=plt.subplots(1)

for i in range(4):
    ax1.scatter(x[y==i,0],x[y==i,1],marker='o',s=8,c=color[i])
#   scatter(x轴,y轴,点的形状,点的大小,点的颜色)

plt.show()

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!