聚类算法k-means(无监督学习)笔记

内容简介

笔记记录了聚类算法k-means的实例过程:

  • 第1部分为建模流程:先构造包含5个中心点的随机训练集数据,并画图展现样本分布情况,最后导入新数据测试;
  • 第2部分介绍了几个常用参数和调优流程;
  • 第3、4部分别为评估方法和算法存在的问题。

1. k-means建模

1) 构造训练集(构造5个数作为中心点),画图显示情况

# 导入模块
import numpy as np
import os
%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
import warnings
warnings.filterwarnings('ignore')
np.random.seed(42)

from sklearn.datasets import make_blobs

#构造5个中心点
blob_centers = np.array(
    [[0.2,2.3],
     [-1.5,2.3],
     [-2.8,1.8],
     [-2.8,2.8],
     [-2.8,1.3]])

#先设置一个半径参数分别是0.4,0.3 和3个0,1
blob_std =np.array([0.4,0.3,0.1,0.1,0.1]) 

#以5个中心点为核心,向外发散画5个簇
X,y = make_blobs(n_samples=2000,centers=blob_centers,
                     cluster_std = blob_std,random_state=7)

#参数解读: cluster_std 从中心向外的发散程度 

#画图
#无监督,不用y
def plot_clusters(X, y=None):
    plt.scatter(X[:, 0], X[:, 1], c=y, s=1)
    plt.xlabel("$x_1$", fontsize=14)
    plt.ylabel("$x_2$", fontsize=14, rotation=0)
plt.figure(figsize=(8, 4))
plot_clusters(X)
plt.show()

聚类算法k-means(无监督学习)笔记_第1张图片

2)模型训练

#实例化模型
from sklearn.cluster import KMeans
k = 5
kmeans = KMeans(n_clusters = k,random_state=42) #建立模型
y_pred =  kmeans.fit_predict(X) #数里没有Y,只有X 
y_pred #把每一个样本点都归类到0-4 一共5个簇里面

fit_predict(X)与kmeans.labels_ 得到预测结果是一致的

kmeans.labels_ 

聚类算法k-means(无监督学习)笔记_第2张图片

kmeans.cluster_centers_ #调用当前簇的中心点,一共5个 

聚类算法k-means(无监督学习)笔记_第3张图片

3)导入新数据测试结果

#导入新数据使用分类器 
#导入4个新数据点[0,2],[3,2],[-3,3],[-3,2.5]让模型分类
X_new = np.array([[0,2],[3,2],[-3,3],[-3,2.5]])
kmeans.predict(X_new)

#transform 每个样本到各个簇中心点的距离
kmeans.transform(X_new) 
#4*5个距离 

聚类算法k-means(无监督学习)笔记_第4张图片

# 数据展示
def plot_data(X):
    plt.plot(X[:, 0], X[:, 1], 'k.', markersize=2)

def plot_centroids(centroids, weights=None, circle_color='w', cross_color='k'):
    if weights is not None:
        centroids = centroids[weights > weights.max() / 10]
    plt.scatter(centroids[:, 0], centroids[:, 1],
                marker='o', s=30, linewidths=8,
                color=circle_color, zorder=10, alpha=0.9)
    plt.scatter(centroids[:, 0], centroids[:, 1],
                marker='x', s=50, linewidths=50,
                color=cross_color, zorder=11, alpha=1)

#画决策边界的函数
def plot_decision_boundaries(clusterer, X, resolution=1000, show_centroids=True,
                             show_xlabels=True, show_ylabels=True):
    mins = X.min(axis=0) - 0.1
    maxs = X.max(axis=0) + 0.1
    xx, yy = np.meshgrid(np.linspace(mins[0], maxs[0], resolution),
                         np.linspace(mins[1], maxs[1], resolution))
    Z = clusterer.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)

    plt.contourf(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
                cmap="Pastel2")  #等高线 
    plt.contour(Z, extent=(mins[0], maxs[0], mins[1], maxs[1]),
                linewidths=1, colors='k') #颜色
    plot_data(X)
    if show_centroids:
        plot_centroids(clusterer.cluster_centers_)

    if show_xlabels:
        plt.xlabel("$x_1$", fontsize=14)
    else:
        plt.tick_params(labelbottom='off')
    if show_ylabels:
        plt.ylabel("$x_2$", fontsize=14, rotation=0)
    else:
        plt.tick_params(labelleft='off')

plt.figure(figsize=(8, 4))
plot_decision_boundaries(kmeans, X)
plt.show()

聚类算法k-means(无监督学习)笔记_第5张图片

2.参数详解与调优流程

这里开始介绍几个常用参数的含义和调优。

参数详解:

  • n_clusters:整型,缺省值=8 ,生成的聚类数。
  • max_iter:整型,缺省值=300 。执行一次k-means算法所进行的最大迭代
  • n_init:整型,缺省值=10 。用不同的聚类中心初始化值运行算法的次数,最终解是在inertia意义下选出的最优结果。
  • init:有三个可选值:’k-means++’, ‘random’,或者传递一个ndarray向量。 此参数指定初始化方法,默认值为 ‘k-means++’。   
    (1)‘k-means++’ 用一种特殊的方法选定初始聚类中发,可加速迭代过程的收敛。
    (2)‘random’ 随机从训练数据中选取初始质心。
    (3)如果传递的是一个ndarray,则应该形如 (n_clusters,
    n_features) 并给出初始质心。
  • precompute_distances:三个可选值,‘auto’,True 或者 False。 预计算距离,计算速度更快但占用更多内存。
    (1)‘auto’:如果 样本数乘以聚类数大于 12million 的话则不预计算距离。
    (2)True:总是预先计算距离。   
    (3)False:永远不预先计算距离。
  • tol:float类型,默认值= 1e-4 与inertia结合来确定收敛条件。
  • n_jobs:整形数。 指定计算所用的进程数。内部原理是同时进行n_init指定次数的计算。
    (1)若值为 -1,则用所有的CPU进行运算。若值为1,则不进行并行运算。
    (2)若值小于-1,则用到的CPU数为(n_cpus + 1 + n_jobs)。因此如果 n_jobs值为-2,则用到的CPU数为总CPU数减1。
  • random_state:整型或 numpy.RandomState 类型,可选。用于初始化质心的生成器(generator)。如果值为一个整数,则确定一个seed。此参数默认值为numpy的随机数生成器。
  • copy_x:布尔型,默认值=True 。 当我们precomputing distances时,将数据中心化会得到更准确的结果。
    (1)如果把此参数值设为True,则原始数据不会被改变。
    (2)如果是False,则会直接在原始数据上做修改并在函数返回值时将其还原。但是在计算过程中由于有对数据均值的加减运算,所以数据返回后,原始数据和计算前可能会有细小差别。

1)找到最佳簇数K:n_clusters

将n_clusters 设置从1-10,然后画图看下不同的n_clusters 对结果有什么影响

#设置K在1-10范围内
kmeans_per_k = [KMeans(n_clusters = k).fit(X) for k in range(1,10)]
inertias = [model.inertia_ for model in kmeans_per_k]

#画图
plt.figure(figsize=(8,4))
plt.plot(range(1,10),inertias,'bo-')
plt.axis([1,8.5,0,1300])
plt.show()

聚类算法k-means(无监督学习)笔记_第6张图片

  • 找到最佳簇数K:如果k值越大,得到的结果肯定会越来越小。心点多,距离必然变小。 因此选择拐点处的取值比较合适, 之后K值再增加没什么变化。
  • 由上图可见, K值=4的时候最好。
  • 但实际上有5个簇,所以这个方法只能作为参考。

2)max_iter

max_iter 执行一次k-means算法所进行的最大迭代,将这个参数分别设置成1、2、3,计算对比结果。

#创建3个模型, 每个5个簇, random随机选择初始位置。n_init跑几次得最佳, random_states随机几次 
#max_iter执行一次k-means算法所进行的最大迭代;这里分别是1、2、3
kmeans_iter1 = KMeans(n_clusters = 5,init = 'random',n_init = 1,max_iter=1,random_state=1)
kmeans_iter2 = KMeans(n_clusters = 5,init = 'random',n_init = 1,max_iter=2,random_state=1)
kmeans_iter3 = KMeans(n_clusters = 5,init = 'random',n_init = 1,max_iter=3,random_state=1)

kmeans_iter1.fit(X)
kmeans_iter2.fit(X)
kmeans_iter3.fit(X)

画图显示决策边界

#画图表示 
#第一次 的中心点
plt.figure(figsize=(12,8))
plt.subplot(321)
plot_data(X)
plot_centroids(kmeans_iter1.cluster_centers_, circle_color='r', cross_color='k')
plt.title('Update cluster_centers')

#第一次的中心点,各个样本的归属,画决策边界
plt.subplot(322)
plot_decision_boundaries(kmeans_iter1, X,show_xlabels=False, show_ylabels=False)
plt.title('Label')

plt.subplot(323)
plot_decision_boundaries(kmeans_iter1, X,show_xlabels=False, show_ylabels=False)
plot_centroids(kmeans_iter2.cluster_centers_,)

plt.subplot(324)
plot_decision_boundaries(kmeans_iter2, X,show_xlabels=False, show_ylabels=False)

plt.subplot(325)
plot_decision_boundaries(kmeans_iter2, X,show_xlabels=False, show_ylabels=False)
plot_centroids(kmeans_iter3.cluster_centers_,)

plt.subplot(326)
plot_decision_boundaries(kmeans_iter3, X,show_xlabels=False, show_ylabels=False)

plt.show()

聚类算法k-means(无监督学习)笔记_第7张图片上图可以看到模型逐步迭代的过程,随着迭代次数不同,中心点慢慢靠近簇心。

3)random_state

random_state用于初始化质心的生成器(generator);如果值为一个整数,则确定一个seed;此参数默认值为numpy的随机数生成器。
这里测试随机种子分别是11和19‘

#画图的
def plot_clusterer_comparison(c1,c2,X):
    c1.fit(X)
    c2.fit(X)
    
    plt.figure(figsize=(12,4))
    plt.subplot(121)
    plot_decision_boundaries(c1,X)
    plt.subplot(122)
    plot_decision_boundaries(c2,X)

#两个新的Kmeans,n_init = 1只做一次,但是random_state随机种子分别是11和19
c1 = KMeans(n_clusters = 5,init='random',n_init = 1,random_state=11)
c2 = KMeans(n_clusters = 5,init='random',n_init = 1,random_state=19)
plot_clusterer_comparison(c1,c2,X)

聚类算法k-means(无监督学习)笔记_第8张图片

  • Kmeans的结果是不稳定的
  • 两边的结果不同,初始位置可能会导致结果不同;所以需要多次迭代测试

3. 评估方法

1)Inertia

Inertia,每个样本与其质心的距离。

kmeans.inertia_

在这里插入图片描述
上面kmeans.inertia_结果输出是 211.5985372581684, 下面代码一步步演示计算过程。

#inertia计算方式
#transform得到的是当前样本到每个簇中心距离
X_dist = kmeans.transform(X)
kmeans.transform(X) 
#每个样本到哪个簇最近,一共有0-4五个簇
kmeans.labels_

X_dist[np.arange(len(X_dist)),kmeans.labels_]

np.sum(X_dist[np.arange(len(X_dist)),kmeans.labels_]**2)

聚类算法k-means(无监督学习)笔记_第9张图片
最终结果都是211.5985372581684。 每个样本到它最近簇距离的平方和加在一起。

Kmeans.score(X)数值也是一样,但是个负值。
聚类算法k-means(无监督学习)笔记_第10张图片
对比c1,c2intertia 值, c1 更小,

2)轮廓系数

轮廓系数
sklearn.metrics.silhouette_score(X, labels, *, metric=‘euclidean’, sample_size=None, random_state=None, **kwds)
结果最好是1,则说明样本i聚类合理;
若最坏为-1,则说明样本i更应该分类到另外的簇;
若近似为0,则说明样本i在两个簇的边界上。

from sklearn.metrics import silhouette_score
silhouette_score(X,kmeans.labels_)

#使用之前用的找K的例子
#kmeans_per_k = [KMeans(n_clusters = k).fit(X) for k in range(1,10)]
kmeans_per_k

#计算结果
silhouette_scores = [silhouette_score(X,model.labels_) for model in kmeans_per_k[1:]]
#可视化展示
plt.figure(figsize=(8,4))
plt.plot(range(2,10),silhouette_scores,'bo-')
plt.show()

聚类算法k-means(无监督学习)笔记_第11张图片结果显示最好的K也是4

4.k-means存在的问题

两个测试方法得到的结果都是K=4, 但是我们设定的簇实际上是有5个。

再做个对比实验看看。

X1, y1 = make_blobs(n_samples=1000, centers=((4, -4), (0, 0)), random_state=42)
X1 = X1.dot(np.array([[0.374, 0.95], [0.732, 0.598]]))
X2, y2 = make_blobs(n_samples=250, centers=1, random_state=42)
X2 = X2 + [6, -8]
X = np.r_[X1, X2]
y = np.r_[y1, y2]

#对比实验 两个模型情况 
kmeans_good = KMeans(n_clusters=3,init=np.array([[-1.5,2.5],[0.5,0],[4,0]]),n_init=1,random_state=42)
kmeans_bad = KMeans(n_clusters=3,random_state=42)
kmeans_good.fit(X)
kmeans_bad.fit(X)

#画图
plt.figure(figsize = (10,4))
plt.subplot(121)
plot_decision_boundaries(kmeans_good,X)
plt.title('Good - inertia = {}'.format(kmeans_good.inertia_))

plt.subplot(122)
plot_decision_boundaries(kmeans_bad,X)
plt.title('Bad - inertia = {}'.format(kmeans_bad.inertia_))

聚类算法k-means(无监督学习)笔记_第12张图片

  • 按照inertia数值,左边的是bad; 但是看图,我们确定左边的图更准确。可见评估标准只能作为参考。

参考网址链接:轮廓系数-https://scikit-learn.org/stable/modules/generated/sklearn.metrics.silhouette_score.html#sklearn.metrics.silhouette_score

你可能感兴趣的:(机器学习算法,聚类,算法,python)