当前位置:   article > 正文

【人工智能基础】聚类实验分析

【人工智能基础】聚类实验分析

实验环境:anaconda、jupyter notebook、spyder

实现用到的类库:numpy、matplotlib、scikit-learn

k均值聚类(K-MEANS)

k均值聚类的原理:

  1. 选定k个聚类中心
  2. 把数据集中距离聚类中心i最近的点都归属到一个簇
  3. 根据每个簇中的点计算出新的聚类中心
  4. 如果聚类中心没有发生移动,则聚类完成,否则重复2,3,4

一、 根据k均值聚类的原理,尝试自己实现

k均值实现类

  1. import math
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. class KMeans:
  5. def __init__(self):
  6. # 聚类的每一步
  7. self.clustering_step = []
  8. def train(self,data, num_clusters):
  9. self.data = data
  10. self.num_clusters = num_clusters
  11. count = data.shape[0]
  12. # 获取初始聚类中心
  13. self.center = self.init_clustering_center()
  14. # 存储原始状态
  15. self.clustering_step.append([np.copy([self.data]),np.copy(self.center)])
  16. # 聚类一次
  17. new_center,cluster = self.updata_clustering_center()
  18. # 如果聚类中心的位置产生了移动继续聚类
  19. while not KMeans.is_equal(new_center, self.center):
  20. self.center = new_center
  21. temp = [cluster,np.copy(self.center)]
  22. self.clustering_step.append(temp)
  23. new_center,cluster = self.updata_clustering_center()
  24. @staticmethod
  25. def is_equal(array1, array2):
  26. for i in range(len(array1)):
  27. if (array1[i][0] - array2[i][0])**2 > 1e-10 and (array1[i][1] - array2[i][1])**2 > 1e-10:
  28. return False
  29. return True
  30. def init_clustering_center(self):
  31. """
  32. 初始化聚类中心
  33. 洗牌数组后随机取k个数值
  34. """
  35. return self.data[np.random.permutation(self.data.shape[0])][:self.num_clusters]
  36. def updata_clustering_center(self):
  37. '''
  38. 更新聚类中心
  39. '''
  40. # 记录每组的点
  41. cluster = []
  42. for _ in range(self.num_clusters):
  43. cluster.append([])
  44. for d in self.data:
  45. distance = []
  46. # 计算每个样本点到假定聚类中心的欧式距离
  47. for c in self.center:
  48. distance.append(np.sum((d - c))**2)
  49. # 每个点分配到最近的聚类中心
  50. min_index = np.argmin(distance)
  51. cluster[min_index].append(d)
  52. new_center = []
  53. # 计算新聚类中心的位置
  54. for c in cluster:
  55. if len(c) == 0:
  56. new_center.append([0,0])
  57. continue
  58. new_center.append(np.sum(c,axis=0) / len(c))
  59. cluster = [np.array(x) for x in cluster]
  60. return new_center,cluster
  61. def show_step(self,row):
  62. '''
  63. 绘制聚类过程
  64. '''
  65. color = ['r','b','y']
  66. step = len(self.clustering_step)
  67. col = math.ceil(step / row)
  68. plt.figure(figsize=(row * 6, col * 5))
  69. for i in range(step):
  70. plt.subplot(row,math.ceil(step / row), i + 1)
  71. current_step = self.clustering_step[i]
  72. group = current_step[0]
  73. center = current_step[1]
  74. for g in group:
  75. plt.scatter(g[:,0], g[:,1])
  76. plt.scatter(center[:,0], center[:,1] ,c='k',marker='x')
  77. plt.title(label='clustering:{}'.format(i+1))
  78. plt.legend()
  79. plt.show()

2.运行k均值算法

这里使用的数据集是鸢尾花数据集

  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from sklearn import datasets
  4. from my_work.k_means import KMeans
  5. iris = datasets.load_iris()
  6. data = iris.data
  7. class_ = iris.target
  8. print(class_)
  9. x_axis = 2
  10. y_axis = 3
  11. x1 = data[:,x_axis]
  12. x2 = data[:,y_axis]
  13. # 绘制原始的图
  14. plt.figure(figsize=(12,5))
  15. plt.subplot(1,2,1)
  16. for iris_type in np.unique(class_):
  17. plt.scatter(x1[class_==iris_type],
  18. x2[class_==iris_type],
  19. label=iris_type)
  20. plt.subplot(1,2,2)
  21. plt.scatter(x1, x2)
  22. plt.legend()
  23. plt.show()
  24. # 绘制经过kmeans算法得到的训练过程
  25. x_train = np.c_[x1,x2]
  26. kmeans = KMeans()
  27. num_clusters = np.unique(class_).shape[0]
  28. kmeans.train(x_train, num_clusters)
  29. kmeans.show_step(3)

3.结果

我们自己实现的算法能够完成k均值分类的任务

鸢尾花数据集真实聚类

鸢尾花数据集k均值算法聚类

二、scikit-learn提供的kmeans算法

1.实验准备

  1. import numpy as np
  2. import os
  3. %matplotlib inline
  4. import matplotlib
  5. import matplotlib.pyplot as plt
  6. plt.rcParams['axes.labelsize'] = 14
  7. plt.rcParams['xtick.labelsize'] = 12
  8. plt.rcParams['ytick.labelsize'] = 12
  9. import warnings
  10. warnings.filterwarnings('ignore')
  11. np.random.seed(42)

2.初始化样本数据集

创建数据集

  1. # 引入椭圆
  2. from sklearn.datasets import make_blobs
  3. # 指定五个中心
  4. blob_centers = np.array(
  5. [[0.2,2.3],
  6. [-1.5,2.3],
  7. [-2.8,1.8],
  8. [-2.8,2.8],
  9. [-2.8,1.3]]
  10. )
  11. blob_std = np.array([0.4,0.3,0.1,0.1,0.1])
  12. x,y = make_blobs(
  13. # 样本个数
  14. n_samples=2000,
  15. # 中心点
  16. centers=blob_centers,
  17. # 发散程度
  18. cluster_std=blob_std,
  19. random_state=7
  20. )

绘制数据集

  1. # 绘图函数
  2. def plot_clusters(x, y= None):
  3. plt.scatter(x[:,0],x[:,1],c=y,s=1)
  4. plt.xlabel('$x_1$',fontsize=14)
  5. plt.ylabel('$x_2$',fontsize=14)
  6. # 绘制图像
  7. plt.figure(figsize=(8,4))
  8. plot_clusters(x)
  9. plt.show()

我们创建了五个聚类中心的数据集

椭圆数据集

3.使用kmeans算法实现聚类

实现聚类

  1. from sklearn.cluster import KMeans
  2. # 聚类中心个数
  3. k = 5
  4. kmeans = KMeans(n_clusters = k, random_state=42,n_init='auto')
  5. # 打印每个点所属的的聚类
  6. print(kmeans.labels_)
  7. print(kmeans.fit_predict(x))
  8. # 打印聚类中心的位置
  9. print(kmeans.cluster_centers_)
  10. # 预测这些点所属的聚类中心
  11. x_new = np.array([[0,2],[3,2],[-3,-3],[-3,2.5]])
  12. print(kmeans.predict(x_new))

绘制函数

  1. def plot_data(x):
  2. """
  3. 绘制入参的图像
  4. """
  5. plt.plot(x[:,0],x[:,1],'k.',markersize=2)
  6. def plot_centroids(centroids, weights=None, circle_color='w',cross_color='k'):
  7. """
  8. 绘制中心点
  9. """
  10. if weights is not None:
  11. centroids = centroids[weights > weights.max() / 10]
  12. plt.scatter(centroids[:,0],
  13. centroids[:,1],
  14. marker='o',
  15. s=30,
  16. linewidths=8,
  17. color=circle_color,
  18. zorder=10,
  19. alpha=0.9)
  20. plt.scatter(centroids[:,0],
  21. centroids[:,1],
  22. marker='x',
  23. s=50,
  24. linewidths=1,
  25. color=cross_color,
  26. zorder=11,
  27. alpha=1)
  28. def plot_decision_boundaries(clusterer, x, resolution=100, show_centroids=True,
  29. show_xlabels=True,show_ylabels=True):
  30. """
  31. 绘制聚类器对参数x的聚类结果
  32. """
  33. mins = x.min(axis=0) - 0.1
  34. maxs = x.max(axis=0) + 0.1
  35. xx,yy = np.meshgrid(np.linspace(mins[0],maxs[0],resolution),
  36. np.linspace(mins[1],maxs[1],resolution))
  37. z = clusterer.predict(np.c_[xx.ravel(),yy.ravel()])
  38. z = z.reshape(xx.shape)
  39. plt.contourf(z, extent=(mins[0],maxs[0],mins[1],maxs[1]), cmap='Pastel2')
  40. plt.contour(z, extent=(mins[0],maxs[0],mins[1],maxs[1]),linewidths=1,colors='k')
  41. plot_data(x)
  42. if show_centroids:
  43. plot_centroids(clusterer.cluster_centers_)
  44. if show_xlabels:
  45. plt.xlabel('$x_1$',fontsize=14)
  46. else:
  47. plt.tick_params(labelbottom='off')
  48. if show_ylabels:
  49. plt.ylabel('$x_2$',fontsize=14,rotation=0)
  50. else:
  51. plt.tick_params(labelleft='off')

绘制聚类结果

  1. plt.figure(figsize=(10,3))
  2. plot_decision_boundaries(kmeans,x)
  3. plt.show()

kmeans聚类结果

三、聚类过程

创建三个kmeans对象,分别进行1,2,3次迭代聚类

  1. kmeans__iter1 = KMeans(n_clusters = 5, init='random',n_init=1, max_iter=1,random_state=1)
  2. kmeans__iter1.fit(x)
  3. kmeans__iter2 = KMeans(n_clusters = 5, init='random',n_init=1, max_iter=2,random_state=1)
  4. kmeans__iter2.fit(x)
  5. kmeans__iter3 = KMeans(n_clusters = 5, init='random',n_init=1, max_iter=3,random_state=1)
  6. kmeans__iter3.fit(x)

绘制图像

  1. plt.figure(figure=(10,8))
  2. plt.subplot(321)
  3. plot_data(x)
  4. plot_centroids(kmeans__iter1.cluster_centers_,circle_color='r',cross_color='k')
  5. plt.title('Update cluster_centers')
  6. plt.subplot(322)
  7. plot_data(x)
  8. plot_decision_boundaries(kmeans__iter1,x,show_xlabels=False,show_ylabels=False)
  9. plt.title('Label')
  10. plt.subplot(323)
  11. plot_decision_boundaries(kmeans__iter1,x,show_xlabels=False,show_ylabels=False)
  12. plot_centroids(kmeans__iter2.cluster_centers_,circle_color='r',cross_color='k')
  13. plt.subplot(324)
  14. plot_decision_boundaries(kmeans__iter2,x,show_xlabels=False,show_ylabels=False)
  15. plt.subplot(325)
  16. plot_decision_boundaries(kmeans__iter2,x,show_xlabels=False,show_ylabels=False)
  17. plot_centroids(kmeans__iter3.cluster_centers_,circle_color='r',cross_color='k')
  18. plt.subplot(326)
  19. plot_decision_boundaries(kmeans__iter3,x,show_xlabels=False,show_ylabels=False)
  20. plt.show()

kmeans聚类过程

四、kmeans的不稳定性

kmeans初始的聚类中心不同可能会得到不同的聚类结果

  1. def plot_clusterer_comparison(c1,c2,x):
  2. c1.fit(x)
  3. c2.fit(x)
  4. plt.figure(figsize=(12,4))
  5. plt.subplot(121)
  6. plot_decision_boundaries(c1,x)
  7. plt.subplot(122)
  8. plot_decision_boundaries(c2,x)
  9. c1 = KMeans(n_clusters = 5, init='random',n_init=1, random_state=11)
  10. c2 = KMeans(n_clusters = 5, init='random',n_init=1, random_state=49)
  11. plot_clusterer_comparison(c1,c2,x)

kmeans不稳定性

五、寻找合适的k值(只是参考)

inertia指标

inertia指标:每个样本与其质心的距离 使用kmeans对象.inertia_来查看

根据inertia指标的转折点

  1. # 获得聚类数为1~10的10个kmeans对象
  2. kmeans_per_k = [KMeans(n_clusters = k).fit(x) for k in range(1,10)]
  3. # 获得这些kmeans对象的inertia指标
  4. interias = [model.inertia_ for model in kmeans_per_k]
  5. # 绘制inertia指标变化图
  6. plt.figure(figsize=(8,4))
  7. plt.plot(range(1,10),interias,'bo-')
  8. plt.show()

根据这个图像,我们认为最佳的聚类数应该是4,实际应该是5,这个指标做为参考,不一定是最优结果

inertia指标变化图

根据轮廓系数

轮廓系数规定参数:

  • ai:计算样本i到同簇其他样本的平均距离。簇内不相似度
  • bi:计算样本到其他某簇Cj的所有样本的平均距离bij。簇间不相似度
  • si = (bi - ai) / max{ai.bi}

由此我们可以知道:

  1. si越接近1,说明样本i聚类合理
  2. si接近-1,说明样本i更应该分到别的簇
  3. si近似为0,说明样本在两个簇的边界
  1. from sklearn.metrics import silhouette_score
  2. scores = [silhouette_score(x, model.labels_) for model in kmeans_per_k[1:]]
  3. plt.figure(figsize=(8,4))
  4. plt.plot(range(2,10),scores,'bo-')
  5. plt.show()

根据这个图像,我们认为最佳的聚类数应该是4,实际应该是5,这个指标做为参考,不一定是最优结果

轮廓系数变化图

六、kmeans进行图像分割

使用的图像是,把这个图像放在python脚本文件相同目录下

ladybug

  1. from matplotlib.image import imread
  2. # 读入图像
  3. image = imread('ladybug.png')
  4. # 图像本身是三维数据,需要转换成二维进行处理
  5. x = image.reshape(-1,3)
  6. # 存储图像分类结果
  7. segmented_imgs = []
  8. # 表示颜色的种类数量
  9. n_colors = (10,8,6,4,2)
  10. # 按不同和的颜色种类数量训练模型
  11. for n_clusters in n_colors:
  12. kmeans = KMeans(n_clusters=n_clusters, random_state=42).fit(x)
  13. # 用聚类中心的颜色来替代整个簇的颜色
  14. segmented_img = kmeans.cluster_centers_[kmeans.labels_]
  15. segmented_imgs.append(segmented_img.reshape(image.shape))
  16. #绘制图像
  17. plt.figure(figsize=(10,5))
  18. plt.subplot(231)
  19. plt.imshow(image)
  20. plt.title('original image')
  21. for idx,n_clusters in enumerate(n_colors):
  22. plt.subplot(232+idx)
  23. plt.imshow(segmented_imgs[idx])
  24. plt.title('{}colors'.format(n_clusters))
  25. plt.show()

kmeans图像分割

DBSCAN

DBSCAN算法:找到图中的核心对象,把核心对象核心对象ε-邻域中的点都聚为一类,若ε-邻域中的点也是核心对象,则继续本类的聚类

  • 核心对象:若某个点的密度达到算法设定的阈值,则其为核心点(r邻域内点的数量不小于minPts)
  • ε-邻域的距离阈值:设定的半径r
  • 直接密度可达:若某点p在点q 的r邻域内,且q是核心点,则称p-q直接密度可达
  • 密度可达:若有一个点的序列q0、q1……qk,对任意qi-qi-1是直接密度可达的,则q0到qk密度可达(直接密度可达的传播)

创建数据集

  1. from sklearn.datasets import make_moons
  2. x, y = make_moons(n_samples=1000,noise=0.05,random_state=42)
  3. plt.plot(x[:,0],x[:,1],'b.')
  4. plt.show()

这个数据集不适合使用kmeans算法进行聚类

DBSCAN数据集

执行聚类学习

  1. from sklearn.cluster import DBSCAN
  2. dbscan = DBSCAN(eps=0.05,min_samples=5)
  3. dbscan.fit(x)
  4. dbscan2 = DBSCAN(eps=0.2,min_samples=5)
  5. dbscan2.fit(x)

图像绘制函数

  1. def plot_dbscan(dbscan,x,size,show_xlabels=True, show_ylabels=True):
  2. core_mask = np.zeros_like(dbscan.labels_,dtype=bool)
  3. core_mask[dbscan.core_sample_indices_]=True
  4. anomalies_mask = dbscan.labels_ == -1
  5. non_core_mask = ~(core_mask | anomalies_mask)
  6. cores=dbscan.components_
  7. anomalies=x[anomalies_mask]
  8. non_cores=x[non_core_mask]
  9. plt.scatter(cores[:,0],cores[:,1],
  10. c=dbscan.labels_[core_mask], marker='o',s=size,cmap='Paired')
  11. plt.scatter(cores[:,0],cores[:,1],marker='*',s=20,c=dbscan.labels_[core_mask])
  12. plt.scatter(non_cores[:,0],non_cores[:,1],c=dbscan.labels_[non_core_mask],marker='.')
  13. if show_xlabels:
  14. plt.xlabel('$x_1$',fontsize=14)
  15. else:
  16. plt.tick_params(labelbottom='off')
  17. if show_ylabels:
  18. plt.ylabel('$x_2$',fontsize=14,rotation=0)
  19. else:
  20. plt.tick_params(labelleft='off')
  21. plt.title('eps={:.2f}, min_samples={}'.format(dbscan.eps, dbscan.min_samples),fontsize=14)

绘制两个DBSCAN聚类器的图像

  1. plt.figure(figsize=(9,4))
  2. plt.subplot(121)
  3. plot_dbscan(dbscan,x,size=100)
  4. plt.subplot(122)
  5. plot_dbscan(dbscan2,x,size=60,show_ylabels=False)
  6. plt.show()

DBSCAN聚类结果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/548970
推荐阅读
相关标签
  

闽ICP备14008679号