机器学习:Kmeans

一、算法原理

  • 根据数据之间是相似的(相关的),将数据分组(簇);
  • 选择K个初始质心(K是簇的个数),每个点指派到最近的质心,而指派到一个质心的点集为一个簇,根据指派到簇的点,更新每个簇的质心,重复指派和更新步骤,直到簇不发生变化或等价地直到质心不发生变化。

二、手写代码

调包:

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn.datasets import make_blobs

模拟数据集:

# 模拟出一些数据集出来
X , Y = make_blobs(n_samples = 300,
                   cluster_std = [0.3, 0.3, 0.3],
                   centers = [[0,0],[1,1],[-1,1]]
                   ,random_state = 4
                  )
sim_data = pd.DataFrame(X, columns = ['x1', 'x2'])
sim_data.head(5)

#画图plt.scatter()
plt.scatter(sim_data['x1'], sim_data['x2'])

1、创建质心

# 自动自动生成随机的质心点
def initial_centers(datasets, k = 3):
    cols = datasets.columns
    data_content = datasets.loc[:, cols != 'label']
    range_info = data_content.describe().loc[['min','max']]
    # np.random.uniform(a, b, c) 随机生成在[a,b)区间里的3个数
    k_randoms = [np.random.uniform(range_info[i]['min'], 
                                   range_info[i]['max'], k) 
                 for i in range_info.columns]
    centers = pd.DataFrame(k_randoms, index = range_info.columns)
    return centers.T

# 手动的创建质心点,无法保证随机性
centers = [[-1.5, 0.5],[1.5, 0],[1, -0.5]]
centers = pd.DataFrame(centers,columns = ["x1","x2"],index = ["blue","green","red"])

2、计算样本点与质心点距离

d = []
for i in centers.index:
    tmp_center = centers.loc[i,:]
    d.append(np.power(sim_data - tmp_center, 2).sum(axis = 1))

3、保持质心不变-更新类别

# 将3个列拼接起来
dis = pd.concat(d,axis = 1)
# 指定列名
dis.columns = centers.index
# 选出每一个样本(或者每一行)里面最小的那个距离所对应的列名
tmp_label = dis.idxmin(axis = 1)
tmp_label.name = "label"
# 更新类别
pd.concat([sim_data,tmp_label], axis = 1)

4、保持类别不变-更新质心

sim_data.groupby(tmp_label).mean()

5、整体代码-循环迭代

#初始化质心点
centers = [[-1.5,0.5],[1.5,0],[1,-0.5]]
centers = pd.DataFrame(centers,columns = ["x1","x2"],index = ["blue","green","red"])

SSE = 0
# 开始迭代
while True:  
    last_SSE = SSE
    # 计算样本点到所有质心的距离
    l = []
    for i in centers.index:
        tmp_center = centers.loc[i,:]
        l.append(np.power(sim_data - tmp_center, 2).sum(axis = 1))
    dis = pd.concat(l,axis = 1)

    # 计算SSE,添加停止条件
    SSE = dis.min(axis = 1).sum()
    if SSE == last_SSE:
        break

    # 保持质心,更新类别
    tmp_label = dis.idxmin(axis = 1)
    tmp_label.name = "label"
    pd.concat([sim_data, tmp_label], axis = 1)
    
    # 保持类别,更新质心
    centers = sim_data.groupby(tmp_label).mean()

三、sklearn算法实现

1、Kmeans算法包

from sklearn.cluster import KMeans
# 训练模型
model = KMeans(n_clusters= 3)    # 实例化
model = model.fit(X)             # 模型学习:将学习到的标签,质心等保存到model里
# 模型学习的结果
model.cluster_centers_  # 质心
model.inertia_          # SSE:所有簇的离散程度之和
model.labels_           # 标签
model.n_iter_           # 迭代次数
dir(model)              # 带一个_的是学习的结果 
# 将聚类的结果和中心点的结果画图表示
plt.scatter(sim_data["x1"], sim_data["x2"], c = model.labels_)
plt.scatter(model.cluster_centers_[: , 0],model.cluster_centers_[:, 1], color = "red")

二、模型评估

1、SSE

SSE评估模型的缺点:

  • 随着k值增大,SSE一直减小,但不代表模型越好;
  • SSE对数据要求满足凸分布,会让聚类算法在一些细长簇,环形簇,或者不规则形状的流形时表现不佳

绘制SSE学习曲线:

iner = []
for i in range(1, 20):
    model = KMeans(n_clusters = i)
    model = model.fit(X)
    iner.append(model.inertia_)

plt.plot(range(1, 20), iner)

2、轮廓系数

  • 样本与其自身所在的簇中的其他样本的相似度a,等于样本与同一簇中所有其他点之间的平均距离;
  • 样本与其他簇中的样本的相似度b,等于样本与下一个最近的簇中的所有点之间的平均距离;
  • 根据聚类的要求 ”簇内差异小,簇外差异大“,希望b大于a,且大得越多越好;
  • 轮廓系数范围(-1,1):
    a:值越接近1表示样本与自己所在的簇中的样本很相似,与其他簇中的样本不相似;
    b:轮廓系数为负,样本点与簇外的样本更相似;
    c:轮廓系数为0,两个簇中的样本相似度一致,两个簇本应该是一个簇;

sklearn调用轮廓系数:

# 尝试使用轮廓系数来查看
from sklearn.metrics import silhouette_score     # 所有轮廓系数均值
from sklearn.metrics import silhouette_samples   # 每个样本轮廓系数

# 给出所有样本点的轮廓系数的均值
silhouette_score(X, model.labels_)

# 给出所有样本点的轮廓系数
# silhouette_samples(X, model.labels_)
# 用轮廓系数绘制学习曲线
sil = []
for i in range(2, 20):
    model = KMeans(n_clusters= i)
    model = model.fit(X)

    sil.append(silhouette_score(X, model.labels_))

plt.plot(range(2, 10), sil[:8])

 --------------------------------------------------------------------------------------------------------------------------------

基于轮廓系数来选择n_clusters:

from sklearn.cluster import KMeans
#from sklearn.metrics import silhouette_samples, sxilhouette_score

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

#先设定我们要分成的簇数
n_clusters = 4

#创建一个画布,画布上共有一行两列两个图
fig, (ax1, ax2) = plt.subplots(1, 2)

#画布尺寸
fig.set_size_inches(18, 7)

# 第一个图是我们的轮廓系数图像,是由各个簇的轮廓系数组成的横向条形图
# 横向条形图的横坐标是我们的轮廓系数取值,纵坐标是我们的每个样本,因为轮廓系数是对于每一个样本进行计算的

# 首先我们来设定横坐标
# 轮廓系数的取值范围在[-1,1]之间,但我们至少是希望轮廓系数要大于0的
# 太长的横坐标不利于我们的可视化,所以只设定X轴的取值在[-0.1,1]之间
ax1.set_xlim([-0.1, 1])

# 接下来设定纵坐标,通常来说,纵坐标是从0开始,最大值取到X.shape[0]的取值
# 但我们希望,每个簇能够排在一起,不同的簇之间能够有一定的空隙
# 以便我们看到不同的条形图聚合成的块,理解它是对应了哪一个簇
# 因此我们在设定纵坐标的取值范围的时候,在X.shape[0]上,加上一个距离(n_clusters + 1) * 10,留作间隔用
ax1.set_ylim([0, X.shape[0] + (n_clusters + 1) * 10])

# 开始建模,调用聚类好的标签
clusterer = KMeans(n_clusters=n_clusters, random_state=10).fit(X)
cluster_labels = clusterer.labels_

# 调用轮廓系数分数,注意,silhouette_score生成的是所有样本点的轮廓系数均值
# 两个需要输入的参数是,特征矩阵X和聚类完毕后的标签
silhouette_avg = silhouette_score(X, cluster_labels)
#用print来报一下结果,现在的簇数量下,整体的轮廓系数究竟有多少
print("For n_clusters =", n_clusters,
      "The average silhouette_score is :", silhouette_avg)

# 调用silhouette_samples,返回每个样本点的轮廓系数,这就是我们的横坐标
sample_silhouette_values = silhouette_samples(X, cluster_labels)

#设定y轴上的初始取值
y_lower = 10

#接下来,对每一个簇进行循环
for i in range(n_clusters):
    # 从每个样本的轮廓系数结果中抽取出第i个簇的轮廓系数,并对他进行排序
    ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
    
    #注意, .sort()这个命令会直接改掉原数据的顺序
    ith_cluster_silhouette_values.sort()
    
    #查看这一个簇中究竟有多少个样本
    size_cluster_i = ith_cluster_silhouette_values.shape[0]
    
    #这一个簇在y轴上的取值,应该是由初始值(y_lower)开始,到初始值+加上这个簇中的样本数量结束(y_upper)
    y_upper = y_lower + size_cluster_i
    
    #colormap库中的,使用小数来调用颜色的函数
    #在nipy_spectral([输入任意小数来代表一个颜色])
    #在这里我们希望每个簇的颜色是不同的,我们需要的颜色种类刚好是循环的个数的种类
    #在这里,只要能够确保,每次循环生成的小数是不同的,可以使用任意方式来获取小数
    #在这里,我是用i的浮点数除以n_clusters,在不同的i下,自然生成不同的小数
    #以确保所有的簇会有不同的颜色
    color = cm.nipy_spectral(float(i)/n_clusters)
    
    #开始填充子图1中的内容
    #fill_between是填充曲线与直角之间的空间的函数
    #fill_betweenx的直角是在纵坐标上
    #fill_betweeny的直角是在横坐标上
    #fill_betweenx的参数应该输入(定义曲线的点的横坐标,定义曲线的点的纵坐标,柱状图的颜色)
    ax1.fill_betweenx(np.arange(y_lower, y_upper)
                      ,ith_cluster_silhouette_values
                      ,facecolor=color
                      ,alpha=0.7
                     )

    #为每个簇的轮廓系数写上簇的编号,并且让簇的编号显示坐标轴上每个条形图的中间位置
    #text的参数为(要显示编号的位置的横坐标,要显示编号的位置的纵坐标,要显示的编号内容)
    ax1.text(-0.05
             , y_lower + 0.5 * size_cluster_i
             , str(i))

    # 为下一个簇计算新的y轴上的初始值,是每一次迭代之后,y的上线再加上10
    #以此来保证,不同的簇的图像之间显示有空隙
    y_lower = y_upper + 10
    
#给图1加上标题,横坐标轴,纵坐标轴的标签
ax1.set_title("The silhouette plot for the various clusters.")
ax1.set_xlabel("The silhouette coefficient values")
ax1.set_ylabel("Cluster label")

#把整个数据集上的轮廓系数的均值以虚线的形式放入我们的图中
ax1.axvline(x=silhouette_avg, color="red", linestyle="--")

#让y轴不显示任何刻度
ax1.set_yticks([])

#让x轴上的刻度显示为我们规定的列表
ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])

#开始对第二个图进行处理,首先获取新颜色,由于这里没有循环,因此我们需要一次性生成多个小数来获取多个颜色
colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)

ax2.scatter(X[:, 0], X[:, 1]
            ,marker='o' #点的形状
            ,s=8 #点的大小
            ,c=colors
           )

#把生成的质心放到图像中去
centers = clusterer.cluster_centers_
# Draw white circles at cluster centers
ax2.scatter(centers[:, 0], centers[:, 1], marker='x',
            c="red", alpha=1, s=200)

#为图二设置标题,横坐标标题,纵坐标标题
ax2.set_title("The visualization of the clustered data.")
ax2.set_xlabel("Feature space for the 1st feature")
ax2.set_ylabel("Feature space for the 2nd feature")

#为整个图设置标题
plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
              "with n_clusters = %d" % n_clusters),
             fontsize=14, fontweight='bold')
plt.show()
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_samples, silhouette_score

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

for n_clusters in [2,3,4,5,6,7]:
    n_clusters = n_clusters
    fig, (ax1, ax2) = plt.subplots(1, 2)
    fig.set_size_inches(18, 7)
    ax1.set_xlim([-0.1, 1])
    ax1.set_ylim([0, X.shape[0] + (n_clusters + 1) * 10])
    clusterer = KMeans(n_clusters=n_clusters, random_state=10).fit(X)
    cluster_labels = clusterer.labels_
    silhouette_avg = silhouette_score(X, cluster_labels)
    print("For n_clusters =", n_clusters,
          "The average silhouette_score is :", silhouette_avg)
    sample_silhouette_values = silhouette_samples(X, cluster_labels)
    y_lower = 10
    for i in range(n_clusters):
        ith_cluster_silhouette_values = sample_silhouette_values[cluster_labels == i]
        ith_cluster_silhouette_values.sort()
        size_cluster_i = ith_cluster_silhouette_values.shape[0]
        y_upper = y_lower + size_cluster_i
        color = cm.nipy_spectral(float(i)/n_clusters)
        ax1.fill_betweenx(np.arange(y_lower, y_upper)
                          ,ith_cluster_silhouette_values
                          ,facecolor=color
                          ,alpha=0.7
                         )
        ax1.text(-0.05
                 , y_lower + 0.5 * size_cluster_i
                 , str(i))
        y_lower = y_upper + 10

    ax1.set_title("The silhouette plot for the various clusters.")
    ax1.set_xlabel("The silhouette coefficient values")
    ax1.set_ylabel("Cluster label")
    ax1.axvline(x=silhouette_avg, color="red", linestyle="--")
    ax1.set_yticks([])
    ax1.set_xticks([-0.1, 0, 0.2, 0.4, 0.6, 0.8, 1])

    colors = cm.nipy_spectral(cluster_labels.astype(float) / n_clusters)
    ax2.scatter(X[:, 0], X[:, 1]
                ,marker='o'
                ,s=8
                ,c=colors
               )
    centers = clusterer.cluster_centers_
    # Draw white circles at cluster centers
    ax2.scatter(centers[:, 0], centers[:, 1], marker='x',
                c="red", alpha=1, s=200)
    
    ax2.set_title("The visualization of the clustered data.")
    ax2.set_xlabel("Feature space for the 1st feature")
    ax2.set_ylabel("Feature space for the 2nd feature")

    plt.suptitle(("Silhouette analysis for KMeans clustering on sample data "
                  "with n_clusters = %d" % n_clusters),
                 fontsize=14, fontweight='bold')
    plt.show()

3、重要参数

初始质心:

  • random_state:控制每次生成的初始质心都在相同位置,可以画学习曲线来确定最优的 random_state;
  • 数init ='kmeans ++':使得初始质心彼此远离,以此来引导出比随机初始化更可靠的结果;

max_iter:最大迭代次数;

tol:两次迭代间Inertia下降的量,如果两次迭代之间Inertia下降的值小于tol所设定的 值,迭代就会停下;

三、DBSCAN

DBSCAN是一种基于密度的聚类方法,旨在寻找被低密度区域分离的高密度区域;

1、基于中心的定义是否相似的方法:

数据集中特定点的密度通过对该点半径之内的点计数(包括点本身)来估计,但点的密度取决于 指定的半径。

点分类:

  • 稠密区域内部的点(核心点):该点的给定领域内的点的个数超过给定的阈值;
  • 稠密区域边缘上的点(边界点):不是核心点,但它落在某个核心点的领域内;
  • 稀疏区域中的点(噪声或背景点):既非核心点也非边界点的任何点;

2、算法原理

任意两个足够靠近(相互之间的距离在Eps之内)的核心点将放在同一个簇中。任何与核心点足够靠近的边界点也放到与核心点相同的簇中(如果一个边界点靠近不同簇的核心点,则可能需要解决平局问题),噪声点被丢弃。

  1. 将所有点标记为核心点、边界点或噪声点;
  2. 删除噪声点;
  3. 为距离在Eps之内的所有核心点之间赋予一条边;
  4. 每个彼此联通的核心点组成一个簇;
  5. 将每个边界点指派到一个与之关联的核心点的簇当中;

3、代码

from sklearn.datasets import make_moons
X,y = make_moons(200, noise = 0.05, random_state=0)
plt.scatter(X[:,0],X[:,1])
from sklearn.cluster import KMeans
kmeans = KMeans(n_clusters=2)
kmeans.fit(X)
centers = kmeans.cluster_centers_
plt.scatter(X[:,0],X[:,1], c = kmeans.labels_)
plt.scatter(centers[:,0], centers[:,1], color= "red")

# 使用DBSCAN
from sklearn.cluster import DBSCAN
db = DBSCAN(eps = 0.3, min_samples = 10)
db.fit(X)
plt.scatter(X[:,0],X[:,1], c = db.labels_)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值