【机器学习】使用scikitLearn对数据进行聚类:Kmeans聚类算法及聚类效果评估

36 篇文章 5 订阅
27 篇文章 3 订阅

无监督学习:
【机器学习】使用scikitLearn对数据进行聚类:Kmeans聚类算法的应用及密度聚类DBSCAN
【机器学习】使用scikitLearn对数据进行聚类:高斯聚类GaussianMixture
【机器学习】使用scikitLearn对数据进行聚类:7种异常和新颖性检测方式

聚类是典型的无监督学习的一种,它将相似的元素聚集在一起。
聚类的应用有很多,比如降维,将一群实例点集聚成K类,每个实例点求对k类的相似度,组成一个k维的向量,如果k小于原来实例的维度,则实现了降维。
当用于异常检测时,也叫离群值检测,请注意,异常值检测时,训练集中会包含异常值,而新颖性检测时,默认训练集都是正常值。
如果使用有标签的算法进行异常值检测,由于异常值极少,类别不平衡,算法很难学习到异常值特征,故一般使用聚类算法,其具体思路是:
轮廓系数较小的实例点或者距离聚类中心最远的点,将其作为离群值点进行关注。
新颖性检测,常用SVM算法,其默认训练数据中没有新颖点。
半监督学习,使用聚类技术,使已有的少数标签数据,在实例中进行扩散。
搜索引擎,先聚类,构造聚类模型,再将原始图片进行聚类操作,聚集出k类,新图片到来时,再用聚类模型对图片进行分类,返回最近类别的全部图片。

KMean算法:
算法的特点是简单,并且高效。
其基本代码为:

from sklearn.cluster import KMeans
k = 5
kmeans = KMeans(n_clusters=k, random_state=42)
y_pred = kmeans.fit_predict(X)

下面查看聚类中心:

kmeans.cluster_centers_

预测新类别:

X_new = np.array([[0, 2], [3, 2], [-3, 3], [-3, 2.5]])
kmeans.predict(X_new)

也可通过计算实例与各个计算中心间距的方法,实现“软投票”。
代码如下:

kmeans.transform(X_new)

通过初始化中心、计算每个集群实例的平均坐标值确定新的中心点,再次将每个实例分配给最近的中心点,算法受随机初始化的中心点影响较大,故多次初始化中心点运行算法吗,取最优值:

#5个聚类中心,运行算法10次,取最优值。
kmeans_rnd_10_inits = KMeans(n_clusters=5, init="random", n_init=10,
                              algorithm="full", random_state=2)
kmeans_rnd_10_inits.fit(X)

上述代码中, n_init=10为默认值,init="random"为随机选定的聚类中心,其不是默认值,默认情况下,kmeans对聚类中心的选择,是按某种概率分布,使初始聚类中心之间的间距尽可能远。algorithm=“full”,为原始算法,elkan K-Means改进算法可以减少原始算法的计算量,默认的auto则会根据数据值是否是稀疏的,来决定如何选择full和elkan。
最优的评价标准是惯性,即每个实例距离其最近的聚类中心的均方距离之和,该值越小越好:

kmeans.inertia_

如果有大致的聚类中心,也可以直接给定:

good_init = np.array([[-3, 3], [-3, 2], [-3, 1], [-1, 2], [0, 2]])
kmeans = KMeans(n_clusters=5, init=good_init, n_init=1, random_state=42)
kmeans.fit(X)
kmeans.inertia_

小批量kmeans的出现降低了内存的占用,使得同一模型可以分批次进行数据训练。

from sklearn.cluster import MiniBatchKMeans
minibatch_kmeans = MiniBatchKMeans(n_clusters=5, random_state=42)
#小批量,每次训练时不使用全部数据,是内部将X拆开了,如果调用partial_fit,是将传递给
#partial_fit的全部X(其实是整体的一部分)进行训练
minibatch_kmeans.fit(X)             

同样的,如果使用memmap进行内存映射,如同在PCA降维中介绍过的,需要指定batchsize,直接使用fit()进行操作:

filename = "my_mnist.data"
X_mm = np.memmap(filename, dtype='float32', mode='write', shape=X_train.shape)
#其实也需要将X_train的数据一次性加载进内存,只不过持久化后训练时分次使用时不再占内存
X_mm[:] = X_train
minibatch_kmeans = MiniBatchKMeans(n_clusters=10, batch_size=10, random_state=42)
minibatch_kmeans.fit(X_mm)

最佳聚类中心数确定:
由于聚类算法的特殊性,惯性会随聚类数的增加持续下降,直到聚类数与实例数相同。
常采用确定聚类中心数目的方法有两个,肘部法及轮廓法:
肘部法,通过作图,找出惯性系数减小趋向平缓的点:

kmeans_per_k = [KMeans(n_clusters=k, random_state=42).fit(X)
                for k in range(1, 10)]
inertias = [model.inertia_ for model in kmeans_per_k]
plt.figure(figsize=(8, 3.5))
plt.plot(range(1, 10), inertias, "bo-")
plt.axis([1, 8.5, 0, 1300])
plt.show()

在这里插入图片描述
看起来k为4时,能取得一个较优的聚类中心数目。
轮廓系数法:
实例的轮廓系数等于(b-a)/max(a,b),其中a是与同一集群中其他实例的平均距离(即集群内平均距离),b是平均最近集群距离(即到下一个最近集群实例的平均距离)。轮廓系数可以在-1和+1之间变化,极端值在a取0及b取0时取得,轮廓系数越接近于1越好。
计算代码如下:

from sklearn.metrics import silhouette_score
kmeans_per_k = [KMeans(n_clusters=k, random_state=42).fit(X)
                for k in range(1, 10)]
#kmeans.labels_为所属索引,不是标签
silhouette_score(X, kmeans.labels_)
silhouette_scores = [silhouette_score(X, model.labels_)
                     for model in kmeans_per_k[1:]]
#绘图
plt.figure(figsize=(8, 3))
plt.plot(range(2, 10), silhouette_scores, "bo-")
plt.xlabel("$k$", fontsize=14)
plt.ylabel("Silhouette score", fontsize=14)
plt.axis([1.8, 8.5, 0.55, 0.7])
plt.show()                     

在这里插入图片描述
可以看出4是比较好的选择。

进一步,结合每类实例数,以及总体轮廓系数,可以绘制轮廓图:

#silhouette_samples返回所有样本的轮廓系数,silhouette_score只返回自己的
from sklearn.metrics import silhouette_samples
from matplotlib.ticker import FixedLocator, FixedFormatter

plt.figure(figsize=(11, 9))
#可能的轮廓系数取值:
for k in (3, 4, 5, 6):
    plt.subplot(2, 2, k - 2)
    #kmeans算法运行后提供的标签号
    y_pred = kmeans_per_k[k - 1].labels_
    silhouette_coefficients = silhouette_samples(X, y_pred)

    padding = len(X) // 30
    pos = padding
    ticks = []
    for i in range(k):
        coeffs = silhouette_coefficients[y_pred == i]
        coeffs.sort()

        color = mpl.cm.Spectral(i / k)
        plt.fill_betweenx(np.arange(pos, pos + len(coeffs)), 0, coeffs,
                          facecolor=color, edgecolor=color, alpha=0.7)
        ticks.append(pos + len(coeffs) // 2)
        pos += len(coeffs) + padding

    plt.gca().yaxis.set_major_locator(FixedLocator(ticks))
    plt.gca().yaxis.set_major_formatter(FixedFormatter(range(k)))
    if k in (3, 5):
        plt.ylabel("Cluster")
    
    if k in (5, 6):
        plt.gca().set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])
        plt.xlabel("Silhouette Coefficient")
    else:
        plt.tick_params(labelbottom=False)

    plt.axvline(x=silhouette_scores[k - 2], color="red", linestyle="--")
    plt.title("$k={}$".format(k), fontsize=16)
plt.show()

运行后会得到如下图形:
在这里插入图片描述
红色虚线为群体平均轮廓系数,最好的状态为k=5时,所有刀形超过红色虚线。

局限性:
当集群具有不同的大小、不同的密度或非球形时,K-Means的表现较差,K-Means算法重点考虑聚类半径,当聚类半径不同时,可以考虑高斯聚类,也因此在聚类前先要进行数据标准化或归一化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颢师傅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值