机器学习之无监督学习(聚类)

一、有中心聚类

1.1 K均值算法

算法思想:随机指定初始中心点,距离中心较近的为一类,不断更新中心点。

【算法原理】
      根据事先给定的聚类数,为每个聚类随机分配中心点,计算所有训练样本与各个中心点的距离,将每个样本分配到与其距离(欧氏距离)最近的中心点所在的聚类中。计算每个聚类的几何中心,用该几何中心为新的聚类中心,重新划分聚类。直到计算出的几何中心与上一次聚类使用的聚类中心重合或者足够接近为止。
《图示》:     
            随机中心点  --->  首次分类后聚类的几何中心 
                                           |                          |
                                          \|/                       \|/
                            与上次中心点重合   与上次中心点不重合
                                           |                          |
                                          \|/                       \|/
                                     分类结束          继续执行聚类划分
                                                                      |
                                                                     \|/
                                                            与上次中心点重合(如不重合,仍继续...)
                                                                      |
                                                                     \|/
                                                                 分类结束
《注意点》
      1、聚类数必须事先已知,(从业务中找,选择最优化指标)
      2、聚类结果会受样本比例的影响
      3、聚类中心的初始位置会影响聚类结果            

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc# 导入数据
x = []
with open('../ML/data/multiple3.txt', 'r') as f:for line in f.readlines():data = [float(substr) for substr in line.split(',')]x.append(data)
# 转为数组
x = np.array(x)# k均值模型
model = sc.KMeans(init='k-means++', n_clusters=4)  # 划分4个中心
# 训练过程包括了k算法的循环过程
model.fit(x)   # 无监督学习 -- 只有输入没有输出
centers = model.cluster_centers_# 聚类边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.05
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.05
grid_x = np.meshgrid(np.arange(l, r, h),np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(),grid_x[1].ravel()]
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)pred_y = model.predict(x)mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=60)mp.scatter(centers[:, 0], centers[:, 1], marker="+",c='gold', s=1000, linewidth=1)
mp.show()

用途示例:图像量化(图像预处理)-- 减少信息量 -- 简化模型

import numpy as np
import scipy.misc as sm
import sklearn.cluster as sc
import matplotlib.pyplot as mp# 读取图片数据,(True)数据转为灰度值
image = sm.imread('../ML/data/lily.jpg',True).astype(np.uint8)
# print(image.shape)   # (512, 512)
# 转变维度
x = image.reshape(-1, 1)
# print(x.shape)   # (262144, 1)
# K均值模型
model = sc.KMeans(n_clusters=2)
model.fit(x)
# 类别标签
y = model.labels_
# print(y.shape)  # (262144,)
centers = model.cluster_centers_
# print(centers.shape)   # (4, 1)
# 删除维度为1的元素
centers = centers.squeeze()
# print(centers.shape)  # (4,)
# 以y中的元素作为下标,在centers中取出对应元素
z = centers[y]
# 维度转化
quant = z.reshape(image.shape)# 显示灰度图像
mp.figure('Original Image', facecolor='lightgray')
mp.title('Original Image', fontsize=20)
# 关闭坐标轴,取消坐标轴显示
mp.axis('off')
mp.imshow(image, cmap='gray')mp.figure('Quant Image', facecolor='lightgray')
mp.title('Quant Image', fontsize=20)
# 关闭坐标轴,取消坐标轴显示
mp.axis('off')
mp.imshow(quant, cmap='gray')
mp.show()

1.2 均值漂移

算法思想:概率最大的点为中心点,分布(曲线/面)覆盖的样本为一类)

【算法原理】:
      把训练样本看成服从某种概率密度函数规则的随机分布,在不断迭代的过程中试图寻找最佳的模式匹配,该密度函数的峰值点就是聚类的中心,为该密度函数所覆盖的样本即隶属于该聚类。
【优势】
       不需要实现给定聚类数,算法本身具有发现聚类数量的能力。

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc# 导入数据
x = []
with open('../ML/data/multiple3.txt', 'r') as f:for line in f.readlines():data = [float(substr) for substr in line.split(',')]x.append(data)
# 转为数组
x = np.array(x)# 均值漂移模型
bw = sc.estimate_bandwidth(x, n_samples=len(x),quantile=0.1)  # quantile精度
model = sc.MeanShift(bandwidth=bw, bin_seeding=True)  # bin_seeding:合并相邻较少的类
# 训练过程
model.fit(x)   # 无监督学习 -- 只有输入没有输出
centers = model.cluster_centers_
# 聚类边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.05
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.05
grid_x = np.meshgrid(np.arange(l, r, h),np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(),grid_x[1].ravel()]
flat_y = model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)pred_y = model.predict(x)# 绘图
mp.figure('Mean Shift Cluster', facecolor='lightgray')
mp.title('Mean Shift Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=60)mp.scatter(centers[:, 0], centers[:, 1], marker="+",c='gold', s=1000, linewidth=1)
mp.show()

二、无中心聚类(凝聚层次)

算法思想:初始每个样本为一类,按距离不断凝聚,达到指定分类数为止。

【算法原理】:
      凝聚层次聚类,可以是自下而上(聚类),也可以是自上而下(分类)。
      1、在自下而上的算法中,每个训练样本都被看做是一个单独的集群,根据样本之间的相似度,将其不断合并,直到集群数达到预先指定的聚类数为止。
      2、在自上而下的算法中,所有训练样本被看做是一个大的聚类,根据样本之间的差异度,将其不断拆分,直到集群数达到指定的聚类数为止。

【凝聚层次】
import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc# 导入数据
x = []
with open('../ML/data/multiple3.txt', 'r') as f:for line in f.readlines():data = [float(substr) for substr in line.split(',')]x.append(data)
# 转为数组
x = np.array(x)# 聚类模型
model = sc.AgglomerativeClustering(n_clusters=4)  # 划分4个中心
# 训练+预测过程
pred_y = model.fit_predict(x)   # 无监督学习 -- 只有输入没有输出mp.figure('Agglomerative Cluster', facecolor='lightgray')
mp.title('Agglomerative Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)mp.grid(linestyle=':')mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=60)
mp.show()

《连续性》
      凝聚层次算法,不同于其它基于中心的聚类算法,用它对一些在空间上具有明显连续性,但彼此间的距离未必最近的样本,可以优先聚集,这样所构成的聚类划分就能够表现出较强的连续特性。
      1、距离最小优先
              按到下一个点的距离最小为聚类依据
      2、方向角度变化最小优先
              按到下一个点的方向该变量最小为聚类依据

【连续性】
import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc
import sklearn.neighbors as nbn_samples = 500
t = 2.5 * np.pi * (1 + 2 * np.random.rand(n_samples, 1))
x = 0.05 * t * np.cos(t)   # 不是等间距的
y = 0.05 * t * np.sin(t)   # 螺旋线方程
# 随机噪声
n = 0.05 * np.random.rand(n_samples, 2)
# 将螺旋线数据与随机噪声混合
x = np.hstack((x, y)) + n# 聚类模型1 -- 无连续性的
model_nonc = sc.AgglomerativeClustering(linkage='average', n_clusters=3)  # 划分4个中心
# 训练+预测过程
pred_y_nonc = model_nonc.fit_predict(x)   # 无监督学习 -- 只有输入没有输出# 聚类模型2 -- 有连续性的
conn = nb.kneighbors_graph(x, 10, include_self=False)  # 从自身出发,找10个紧邻不包括自己
model_conn = sc.AgglomerativeClustering(linkage='average', n_clusters=3, connectivity=conn)
pred_y_conn = model_conn.fit_predict(x)# 绘图
mp.figure('Noneconnectivity Cluster', facecolor='lightgray')
mp.title('Noneconnectivity Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
mp.scatter(x[:, 0], x[:, 1], c=pred_y_nonc, cmap='brg', s=30)
mp.scatter(x[:, 0], x[:, 1], c=pred_y_conn, cmap='brg', s=30)
# 坐标轴等值
mp.axis('equal')
mp.show()

三、DBSCAN-密度聚类

算法思想:朋友的朋友也是朋友。

【算法原理】
      从任何一个训练样本出发,以一个事先给定的半径做圆,凡是不在此圆之外的样本都与圆心样本同类,再以这些同类样本为中心做圆,重复以上过程,直到没有新的同类样本加入该聚类为止。以此类推,获得样本空间中的所有聚类。

《三类样本点》
      1、偏离样本  --  不属于任何聚类的样本;
      2、外围样本  --  位于聚类边缘的样本;
      3、可新样本  --  位于聚类内部的样本;

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc
x = []
with open('../ML/data/perf.txt', 'r') as f:for line in f.readlines():data = [float(substr) for substrin line.split(',')]x.append(data)
x = np.array(x)# DBSCAN模型
model = sc.DBSCAN(eps=0.8, min_samples=5)  # 圆的半径为0.8,一个聚类最少包括5个样本
# 训练+预测过程
pred_y = model.fit_predict(x)   # 无监督学习 -- 只有输入没有输出# 分出三类样本
core_mask = np.zeros(len(x), dtype=bool)  # 空容器
core_mask[model.core_sample_indices_] = True      # 核心样本 索引 - 掩码(置为1)
offset_mask = model.labels_ == -1           # 偏离样本 -- 类标签为-1
periphery_mask = ~(core_mask | offset_mask)   # 排除核心和偏离即为边缘样本# 绘图
mp.figure('DBSCAN Cluster', facecolor='lightgray')
mp.title('DBSCAN Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)
mp.grid(linestyle=':')
labels = set(pred_y)   # 得到所有的标签
cs = mp.get_cmap('brg', len(labels))(range(len(labels)))  # 把映射色带等分
# 核心样本散点图
mp.scatter(x[core_mask][:, 0], x[core_mask][:, 1],c=cs[pred_y[core_mask]], s=60, label='Core')
# 外周样本散点图
mp.scatter(x[periphery_mask][:, 0], x[periphery_mask][:, 1],edgecolor=cs[pred_y[periphery_mask]], s=60,facecolor='none', label='Periphery')
# 孤立样本散点图
mp.scatter(x[offset_mask][:, 0], x[offset_mask][:, 1],c=cs[pred_y[offset_mask]], marker='x', s=60,label='Offset_mask')
mp.legend()
mp.show()

四、模型评价指标

算法思想: 表示聚类划分内密外疏的程度。

《两个指标》 :    
    1、轮廓系数由一下两个指标构成:
      【a】:一个样本与其所在聚类其它样本的平均距离。
      【b】:一个样本与其距离最近的另一个聚类中样本的平均距离。
    2、针对一个样本的轮廓系数:
           s = (b-a)/max(a, b)
    3、针对一个数据集,其轮廓系数就是其中所有样本的轮廓系数的平均值。
    4、轮廓系数的值介于[-1, 1]区间, 
                  -->  1表示完美聚类,-1表示错误聚类,0表示聚类重叠。

import numpy as np
import matplotlib.pyplot as mp
import sklearn.cluster as sc
import sklearn.metrics as sm# 导入数据
x = []
with open('../ML/data/perf.txt', 'r') as f:for line in f.readlines():data = [float(substr) for substr in line.split(',')]x.append(data)
# 转为数组
x = np.array(x)
# 选择范围
clstrs, scores, models = np.arange(2, 11), [], []for n_clusters in clstrs:# k均值模型model = sc.KMeans(init='k-means++',n_clusters=n_clusters)  # 划分4个中心# 训练过程包括了k算法的循环过程model.fit(x)   # 无监督学习 -- 只有输入没有输出score = sm.silhouette_score(x, model.labels_, sample_size=len(x),metric='euclidean')  # 欧式距离scores.append(score)models.append(model)
scores = np.array(scores)
best_index = scores.argmax()
best_clstr = clstrs[best_index]
best_model = models[best_index]
centers = model.cluster_centers_# 聚类边界
l, r, h = x[:, 0].min() - 1, x[:, 0].max() + 1, 0.05
b, t, v = x[:, 1].min() - 1, x[:, 1].max() + 1, 0.05
grid_x = np.meshgrid(np.arange(l, r, h),np.arange(b, t, v))
flat_x = np.c_[grid_x[0].ravel(),grid_x[1].ravel()]
flat_y = best_model.predict(flat_x)
grid_y = flat_y.reshape(grid_x[0].shape)pred_y = best_model.predict(x)mp.figure('K-Means Cluster', facecolor='lightgray')
mp.title('K-Means Cluster', fontsize=20)
mp.xlabel('x', fontsize=14)
mp.ylabel('y', fontsize=14)
mp.tick_params(labelsize=10)mp.pcolormesh(grid_x[0], grid_x[1], grid_y, cmap='gray')mp.scatter(x[:, 0], x[:, 1], c=pred_y, cmap='brg', s=60)mp.scatter(centers[:, 0], centers[:, 1], marker="+",c='gold', s=1000, linewidth=1)
mp.show()

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部