Python大数据分析——DBSCAN聚类模型(密度聚类)

介绍

Kmeans聚类存在两个致命缺点,一是聚类效果容易受到异常样本点的影响(因为求的是均值,而异常值对于均值聚类非常容易受到异常点影响);二是该算法无法准确地将非球形样本进行合理的聚类。
基于密度的聚类则可以解决非球形簇的问题,“密度”可以理解为样本点的紧密程度,如果在指定的半径领域内,实际样本量超过给定的最小样本量阈值,则认为是密度高的对象,就可以聚成一个簇。

数学基础

对于几个数学概念我们做下讲解:
在这里插入图片描述
直接密度可达:是在领域内的点到中心点;
密度可达:是各个领域的中心点,也就是核心点直接的距离;
举例说明:
在这里插入图片描述
除此之外还有四点数学概念:
在这里插入图片描述
举例说明:
在这里插入图片描述
在这里插入图片描述

模型步骤

  1. 为密度聚类算法设置一个合理的半径c以及ε领域内所包含的最少样本量MinPts。
  2. 从数据集中随机挑选一个样本点p,检验其在ε领域内是否包含指定的最少样本量,如果包含就将其定性为核心对象,并构成一个簇C;否则,重新挑选一个样本点。
  3. 对于核心对象p所覆盖的其他样本点q,如果点q对应的ε领域内仍然包含最少样本量MinPts,就将其覆盖的样本点统统归于簇C。
  4. 重复步骤(3),将最大的密度相连所包含的样本点聚为一类,形成一个大簇。
  5. 完成步骤(4)后,重新回到步骤(2),并重复步骤(3)和(4),直到没有新的样本点可以生成新簇时算法结束。

这个模型的缺点就是我们需要靠经验得到合理半径c,而无其他办法。

函数

cluster.DBSCAN(eps=0.5, min_samples=5, metric=‘euclidean’, p=None)
eps:用于设置密度聚类中的e领域,即半径,默认为0.5
min_samples:用于设置e领域内最少的样本量,默认为5
metric:用于指定计算点之间距离的方法,默认为欧氏距离
p:当参数metric为闵可夫斯基(‘minkowski’)距离时,p=1,表示计算点之间的曼哈顿距离;p=2,表示计算点之间的欧氏距离;该参数的默认值为2

密度聚类对比Kmeans聚类

球形簇聚类情况

Kmeans聚类效果:
在这里插入图片描述
密度聚类效果:
在这里插入图片描述
我们发现密度聚类能排除这个异常值点,说明效果更好。

非球形簇的情况

Kmeans聚类效果:
在这里插入图片描述
密度聚类效果:
在这里插入图片描述
发现非球形要用密度聚类

示例

  1. 导入功能包
# 导入第三方模块
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import cluster

注:
在最新的sklearn版本中导入模块from sklearn.datasets.samples_generator import make_blobs时报错:ModuleNotFoundError: No module named ‘sklearn.datasets.samples_generator’,因为已经删除samples_generator了,我们需要改为from sklearn.datasets import make_blobs

  1. 读取数据,查看分布
# 读取外部数据
Province = pd.read_excel(r'D:\pythonProject\data\Province.xlsx')
Province.head()
# 绘制出生率与死亡率散点图
plt.scatter(Province.Birth_Rate, Province.Death_Rate, c = 'steelblue')
# 添加轴标签
plt.xlabel('Birth_Rate')
plt.ylabel('Death_Rate')
# 显示图形
plt.show()

在这里插入图片描述

  1. 数据处理
    首先进行标准化处理(对于量纲不一致的必须需要进行标准化处理,但这里都是百分比其实可以不做的):
# 读入第三方包
from sklearn import preprocessing
# 选取建模的变量
predictors = ['Birth_Rate','Death_Rate']
# 变量的标准化处理
X = preprocessing.scale(Province[predictors])
X = pd.DataFrame(X)

再循环迭代ε,也就是eps,对每一次组合进行一次聚类,从而寻找最佳组合:

# 构建空列表,用于保存不同参数组合下的结果
res = []
# 迭代不同的eps值
for eps in np.arange(0.001,1,0.05):
    # 迭代不同的min_samples值
    for min_samples in range(2,10):
        dbscan = cluster.DBSCAN(eps = eps, min_samples = min_samples)
        # 模型拟合
        dbscan.fit(X)
        # 统计各参数组合下的聚类个数(-1表示异常点)
        n_clusters = len([i for i in set(dbscan.labels_) if i != -1])
        # 异常点的个数
        outliners = np.sum(np.where(dbscan.labels_ == -1, 1,0))
        # 统计每个簇的样本个数
        stats = str(pd.Series([i for i in dbscan.labels_ if i != -1]).value_counts().values)
        res.append({'eps':eps,'min_samples':min_samples,'n_clusters':n_clusters,'outliners':outliners,'stats':stats})
# 将迭代后的结果存储到数据框中        
df = pd.DataFrame(res)
df

在这里插入图片描述
其中eps是ε也就是范围;min_simples指定的最小样本量;n_clusters形成的簇的数量;outliners形成的异常点的个数;stats一个簇的里面的样本个数

我们根据经验:簇类均匀,不要让异常点过多,也就是综合平均选择参数。我们挑选到3可能是适合的

# 根据条件筛选合理的参数组合
df.loc[df.n_clusters == 3, :]

在这里插入图片描述
通过发现每个簇的样本数量不要差异太大,发现0.801是合适的,也就是[17 7 3]

  1. 结果分类
    通过上面分析的数据得到的我们认为可靠的参数值,来拟合分析分类
# 中文乱码和坐标轴负号的处理
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

# 利用上述的参数组合值,重建密度聚类算法
dbscan = cluster.DBSCAN(eps = 0.801, min_samples = 3)
# 模型拟合
dbscan.fit(X)
Province['dbscan_label'] = dbscan.labels_
# 绘制聚类聚类的效果散点图
sns.lmplot(x = 'Birth_Rate', y = 'Death_Rate', hue = 'dbscan_label', data = Province,
           markers = ['*','d','^','o'], fit_reg = False, legend = False)
# 添加省份标签
for x,y,text in zip(Province.Birth_Rate,Province.Death_Rate, Province.Province):
    plt.text(x+0.1,y-0.1,text, size = 8)
# 添加参考线
plt.hlines(y = 5.8, xmin = Province.Birth_Rate.min(), xmax = Province.Birth_Rate.max(), 
           linestyles = '--', colors = 'red')
plt.vlines(x = 10, ymin = Province.Death_Rate.min(), ymax = Province.Death_Rate.max(), 
           linestyles = '--', colors = 'red')
# 添加轴标签
plt.xlabel('Birth_Rate')
plt.ylabel('Death_Rate')
# 显示图形
plt.show()

在这里插入图片描述
五角星代表的是四个异常值,其余的分布为类别

我们可以对比下Kmeans聚类来分析下(这里面采用的是轮廓系数法):

  1. 首先轮廓系数法分析
# 导入第三方模块
from sklearn import metrics
# 构造自定义函数,用于绘制不同k值和对应轮廓系数的折线图
def k_silhouette(X, clusters):
    K = range(2,clusters+1)
    # 构建空列表,用于存储个中簇数下的轮廓系数
    S = []
    for k in K:
        kmeans = cluster.KMeans(n_clusters=k)
        kmeans.fit(X)
        labels = kmeans.labels_
        # 调用字模块metrics中的silhouette_score函数,计算轮廓系数
        S.append(metrics.silhouette_score(X, labels, metric='euclidean'))

    # 中文和负号的正常显示
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    # 设置绘图风格
    plt.style.use('ggplot')    
    # 绘制K的个数与轮廓系数的关系
    plt.plot(K, S, 'b*-')
    plt.xlabel('簇的个数')
    plt.ylabel('轮廓系数')
    # 显示图形
    plt.show()
    
# 聚类个数的探索
k_silhouette(X, clusters = 10)

在这里插入图片描述
发现类别数为3是合适的

  1. 利用Kmeans聚类分析
    通过得到的K值,来拟合分析,查看聚类效果:
# 利用Kmeans聚类
kmeans = cluster.KMeans(n_clusters = 3)
# 模型拟合
kmeans.fit(X)
Province['kmeans_label'] = kmeans.labels_
# 绘制Kmeans聚类的效果散点图
sns.lmplot(x = 'Birth_Rate', y = 'Death_Rate', hue = 'kmeans_label', data = Province,
           markers = ['d','^','o'], fit_reg = False, legend = False)
# 添加轴标签
plt.xlabel('Birth_Rate')
plt.ylabel('Death_Rate')
plt.show()

在这里插入图片描述
所不同的是,有无异常点和这些点的归属问题

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥都鼓捣的小yao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值