聚类分析

scikit-learn的sklearn.cluster模块提供了多种聚类方法

  • K-means聚类
  • 仿射传播聚类
  • 均值漂移聚类
  • 谱聚类
  • 凝聚聚类
  • 密度聚类
  • 高斯混合聚类
  • 层次聚类

K-means聚类分析

K-means聚类分析可以使用KMeans()类和k_means方法。

使用KMeans类进行聚类

KMeans()类的格式如下:

class sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1, algorithm='auto')

KMeans()类的主要参数:
image.png
KMeans()类的主要属性有:
image.png
KMeans()类提供了fit(), predict()等8个方法供数据拟合、预测等使用。
在利用肘部法则确定K值时需要建立聚类效果的指标,这时长长会用到求解两个向量之间距离的cdist()方法。格式如下:

scipy.spatial.distance.cdist(XA,XB,metric='euclidean',V=None,VI=None,w=None)

返回值为XA向量到XB中各向量之间的距离。metric表示距离计算方法。

#%%

#例10-2 使用肘部法则确定最佳K值,
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#使用样本生成器生成数据集
#使用make_blobs生成centers个类的数据集X,X形状为(n_samples,n_features)
#指定每个类的中心位置,y返回类标签
from sklearn.datasets.samples_generator import make_blobs
centers = [(-2, 0), (2, 2)]
X, y = make_blobs(n_samples=100, centers=centers, n_features=2,
random_state=0)
#获取类标签的索引,用于将样本按类绘制
index_y0,index_y1=np.where(y==0),np.where(y==1)
#可视化
plt.rc('font', size=14)#设置图中字号大小
plt.rcParams['font.sans-serif'] = 'SimHei'#设置字体为SimHei显示中文
plt.rcParams['axes.unicode_minus']=False#坐标轴刻度显示负号
p = plt.figure(figsize=(12,4))
#绘制子图1:两个类的原始数据
ax1 = p.add_subplot(1,2,1)
plt.scatter(X[index_y0,0], X[index_y0,1],c='k',marker='.')
plt.scatter(X[index_y1,0], X[index_y1,1],c='k',marker='*')
plt.legend(['类0','类1'])
plt.title('两个类的原始数据')
#定义函数,计算K值从1到10对应的平均畸变程度,寻找较好的聚类数目K
def DrawElbowKMeans(X):
#导入KMeans模块
from sklearn.cluster import KMeans
#导入scipy,求解距离
from scipy.spatial.distance import cdist
K=range(1,10)
meandistortions=[]
for k in K:
kmeans=KMeans(n_clusters=k)
kmeans.fit(X)
meandistortions.append(sum(np.min(
cdist(X,kmeans.cluster_centers_,
'euclidean'),axis=1))/X.shape[0])
import matplotlib.pyplot as plt
plt.grid(True)
plt.plot(K,meandistortions,'kx-')
plt.xlabel('k')
plt.ylabel(u'平均畸变程度')
plt.title(u'用肘部法则来确定最佳的K值')
#plt.show()
#绘制子图2,肘部法则寻找最佳K值
ax2 = p.add_subplot(1,2,2)

DrawElbowKMeans(X=X)
plt.show()

在利用K-meanns方法对数据进行聚类分析时需要注意的一个问题是数据聚类后的簇标签和聚类前数据集的类标签未必完全一致,极有可能在分类前是类标签是0和1聚类后变成了1和0,这个问题在进行聚类分析可视化时一定要注意。一种比较统一的方法是将聚类后的标签合并给原数据集,然后将合并的集合按照类标签或者簇标签分类可视化,分类效果相对会明显很多。

#%%

#例10-4 对两个分类样本进行聚类,使用肘部法则确定最佳K值,
#使用特征集进行聚类,使用类标签对聚类结果进行对比
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#使用样本生成器生成数据集
#使用make_blobs生成centers个类的数据集X,X形状为(n_samples,n_features)
#指定每个类的中心位置,y返回类标签
from sklearn.datasets.samples_generator import make_blobs
centers = [(-2, 0), (2, 2)]
X, y = make_blobs(n_samples=100, centers=centers, n_features=2,
random_state=0)
#获取类标签的索引,用于将样本按类绘制
index_y0,index_y1=np.where(y==0),np.where(y==1)
#可视化
plt.rc('font', size=14)#设置图中字号大小
plt.rcParams['font.sans-serif'] = 'SimHei'#设置字体为SimHei显示中文
plt.rcParams['axes.unicode_minus']=False#坐标轴刻度显示负号
p = plt.figure(figsize=(12,8))
#绘制子图1:两个类的原始数据
ax1 = p.add_subplot(2,2,1)
plt.scatter(X[index_y0,0], X[index_y0,1],c='k',marker='.')
plt.scatter(X[index_y1,0], X[index_y1,1],c='k',marker='*')
plt.legend(['类0','类1'])
plt.title('两个类的原始数据')
#绘制子图2,肘部法则寻找最佳K值
ax2 = p.add_subplot(2,2,2)
DrawElbowKMeans(X=X)
from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
data = X#提取数据集中的特征
scale = MinMaxScaler().fit(data)# 训练规则
dataScale = scale.transform(data)# 应用规则,极差标准化数据
kmeans = KMeans(n_clusters = 2).fit(dataScale)#构建并训练模型
#绘制子图3:K均值聚类结果
labels= kmeans.labels_ #提取聚类结果的类标签
#获取每个样本的簇标签的索引,获取簇0和簇1
index_label0,index_label1=np.where(labels==0),np.where(labels==1)
ax = p.add_subplot(2,2,3)
#簇0、簇1可能是原始数据的类0、类1,也可能是类1、类0,将其调整一致以便对比
#分别求取簇0(或1)与类0(或1)的众数,若二者若相等则说明类、簇编号相同;
#若不等则说明类、簇编号相反,此时更换簇标签,使之与类标签一致。
#转化为DataFrame对象使用mode求取众数
label0_mode=pd.DataFrame(labels[index_label0]).mode(axis=0)
y0_mode=pd.DataFrame(y[index_label0]).mode(axis=0)
if label0_mode.values!=y0_mode.values:
labels[index_label0]=1
labels[index_label1]=0
plt.scatter(X[index_label0,0], X[index_label0,1],c='k',marker='.')
plt.scatter(X[index_label1,0], X[index_label1,1],c='k',marker='*')
plt.legend(['簇0','簇1'])
plt.title('K均值聚类结果')
#子图4,聚类结果与原类别的对比
ax = p.add_subplot(2,2,4)
#获取错误聚类样本的索引
index_wrong=np.where(labels!=y)
plt.scatter(X[index_y0,0], X[index_y0,1],c='k',marker='.')
plt.scatter(X[index_y1,0], X[index_y1,1],c='k',marker='*')
plt.scatter(X[index_wrong,0], X[index_wrong,1],c='k',marker='x',s=80,
facecolors='none', zorder=10, edgecolors='b')
plt.legend(['原类0','原类1','聚类错误'])
plt.title('聚类错误样本与原类别的对比')
plt.show()

多分类样本的可视化

#%%

#例10-5 对4个分类样本进行聚类,使用肘部法则确定最佳K值,
#使用特征集进行聚类,使用类标签对聚类结果进行对比
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
#使用样本生成器生成数据集,生成单标签样本
#使用make_blobs生成centers个类的数据集X,X形状为(n_samples,n_features)
#指定每个类的中心位置,y返回类标签
from sklearn.datasets import make_blobs
centers = [(-3, 0), (3, 2), (-4, 5), (0, 6)]
X, y = make_blobs(n_samples=500, centers=centers, n_features=2,
random_state=0)
print('数据集X的形状为:',X.shape)

#%%

#可视化
plt.rc('font', size=14)#设置图中字号大小
plt.rcParams['font.sans-serif'] = 'SimHei'#设置字体为SimHei显示中文
plt.rcParams['axes.unicode_minus']=False#坐标轴刻度显示负号
#肘部法则确定最佳K值
plt.figure(figsize=(6,4))
DrawElbowKMeans(X=X)
plt.show

#%%

from sklearn.preprocessing import MinMaxScaler
from sklearn.cluster import KMeans
data = X#提取数据集中的特征
scale = MinMaxScaler().fit(data)# 训练规则,标准化数据
dataScale = scale.transform(data)# 应用规则
kmeans = KMeans(n_clusters = 4).fit(dataScale)#构建并训练模型
#获取类标签的索引,用于将样本按类绘制
index_y0,index_y1=np.where(y==0),np.where(y==1)
index_y2,index_y3=np.where(y==2),np.where(y==3)
labels= kmeans.labels_ #提取聚类结果的类标签
#获取簇标签的索引,用于将样本按簇绘制
index_label0,index_label1=np.where(labels==0),np.where(labels==1)
index_label2,index_label3=np.where(labels==2),np.where(labels==3)
#可视化原始数据类别与聚类结果,进行对比
p=plt.figure(figsize=(12,4))
#子图1:绘制原始类别数据
ax = p.add_subplot(1,2,1)
plt.scatter(X[index_y0,0], X[index_y0,1],c='k',marker='.')
plt.scatter(X[index_y1,0], X[index_y1,1],c='k',marker='o')
plt.scatter(X[index_y2,0], X[index_y2,1],c='k',marker='*')
plt.scatter(X[index_y3,0], X[index_y3,1],c='k',marker='v')
plt.legend(['类0','类1','类2','类3'])
plt.title('原始样本类别')
#子图2:绘制聚类结果
ax = p.add_subplot(1,2,2)
plt.scatter(X[index_label0,0], X[index_label0,1],c='k',marker='.')
plt.scatter(X[index_label1,0], X[index_label1,1],c='k',marker='o')
plt.scatter(X[index_label2,0], X[index_label2,1],c='k',marker='*')
plt.scatter(X[index_label3,0], X[index_label3,1],c='k',marker='v')
plt.legend(['簇0','簇1','簇2','簇3'])
plt.title('聚类结果')
plt.show()

#%%

#将原始数据与类标签、簇标签合并为一个数据集,
#按类别组织数据,对比类标签与簇标签,观察聚类结果
print('原始数据集X的形状为:',X.shape)
X_yl=np.hstack((X,y.reshape(-1,1),labels.reshape(-1,1)))
print('原始数据集与类标签、聚类标签合并后的数据集X_yl的形状为:',X_yl.shape)
print('原始数据集与类标签、聚类标签合并后的数据集X_yl的前5行为:\n',X_yl[0:5,:])

#%%

#获取类标签的索引,用于将样本按类绘制
index_0,index_1=np.where(X_yl[:,2]==0),np.where(X_yl[:,2]==1)
index_2,index_3=np.where(X_yl[:,2]==2),np.where(X_yl[:,2]==3)
X_yl1=np.vstack((X_yl[index_0],X_yl[index_1],X_yl[index_2],X_yl[index_3]))
print('原始数据集按类组织后的数据集X_yl1的形状为:',X_yl1.shape)
print('原始数据集按类组织后的数据集X_yl1的前5行为:\n',X_yl1[0:5,:])

#%%

#可视化,观察聚类结果
plt.figure(figsize=(12,4))#设置画布
plt.scatter(range(y.size), X_yl1[:,2], c='k',marker='.')
plt.scatter(range(y.size), X_yl1[:,3]+.2, c='k',marker='x')#适当错开,便于观察
plt.grid(True)
plt.xlim((0,y.size))
plt.xlabel('样本序号')
plt.ylabel('分类/聚类标签')
plt.title('聚类结果与原始分类结果对比')
plt.legend(['原始分类','聚类结果'])
plt.show()