Py学习  »  Python

从零开始学Python【31】—DBSCAN聚类(实战部分)

数据分析1480 • 5 年前 • 627 次点击  

前言


在《从零开始学Python【30】--DBSCAN聚类(理论部分)》一文中我们侧重介绍了有关密度聚类的理论知识,涉及的内容包含密度聚类中的一些重要概念(如核心对象、直接密度可达、密度相连等)和密度聚类的具体步骤。在本次文章中,我们将通过一个小的数据案例,讲解如何基于Python实现密度聚类的实战。

函数说明


在Python的sklearn模块中,cluster子模块集成了常用的聚类算法,如K均值聚类、密度聚类和层次聚类等。对于密度聚类而言,读者可以直接调用cluster子模块中的DBSCAN“类”,有关该“类”的语法和参数含义如下:

cluster.DBSCAN(eps=0.5, min_samples=5, metric='euclidean',
               metric_params=None, algorithm='auto', 
               leaf_size=30, p=None, n_jobs=1)
eps:用于设置密度聚类中的ε领域,即半径,默认为0.5;
min_samples:用于设置ε领域内最少的样本量,默认为5;
metric:用于指定计算点之间距离的方法,默认为欧氏距离;
metric_params:用于指定metric所对应的其他参数值;
algorithm:在计算点之间距离的过程中,用于指点搜寻最近邻样本点的算法;默认为'auto',表示密度聚类会自动选择一个合适的搜寻方法;如果为'ball_tree',则表示使用球树搜寻最近邻;如果为'kd_tree',则表示使用K-D树搜寻最近邻;如果为'brute',则表示使用暴力法搜寻最近邻;
leaf_size:当参数algorithm为'ball_tree''kd_tree'时,用于指定树的叶子节点中所包含的最多样本量,默认为30;该参数会影响搜寻树的构建和搜寻最近邻的速度;
p:当参数metric为闵可夫斯基距离时('minkowski'),p=1,表示计算点之间的曼哈顿距离;p=2,表示计算点之间的欧氏距离;该参数的默认值为2;
n_jobs:用于设置密度聚类算法并行计算所需的CPU数量,默认为1表示仅使用1个CPU运行算法,即不使用并行运算功能;

需要说明的是,在DBSCAN“类”中,参数eps和min_samples需要同时调参,即通常会指定几个候选值,并从候选值中挑选出合理的阈值;在参数eps固定的情况下,如果参数min_samples越大,所形成的核心对象就越少,往往会误判出许多异常点,聚成的簇数目也会增加,反之,会产生大量的核心对象,导致聚成的簇数目减少;在参数min_samples固定的情况下,参数eps越大,就会导致更多的点落入到ε领域内,进而使核心对象增多,最终使聚成的簇数目减少,反之,会导致核心对象大量减少,最终聚成的簇数目增多。在参数eps和min_samples不合理的情况下,簇数目的增加或减少往往都是错误的,例如应该聚为一类的样本由于簇数目的增加而聚为多类;不该聚为一类的样本由于簇数目的减少而聚为一类。

算法实战


在密度聚类算法的实战部分,我们将使用国内31个省份的人口出生率和死亡率数据作为分析对象。首先,将数据读入到Python中,并绘制出生率和死亡率数据的散点图,代码如下:

# 导入模块
import pandas as pd
form matplotlib.pyplot as plt

# 读取外部数据
Province = pd.read_excel(r'C:\Users\Administrator\Desktop\Province.xlsx') Province.head()
# 绘制出生率与死亡率散点图
plt.scatter(Province.Birth_Rate, Province.Death_Rate)
# 添加轴标签
plt.xlabel('Birth_Rate') plt.ylabel('Death_Rate')
# 显示图形plt.show()

上图所示,31个点分别代表了各省份人口的出生率和死亡率,通过肉眼,就能够快速地发现三个簇,即图中的虚线框,其他不在圈内的点可能就是异常点了。接下来利用密度聚类对该数据集进行验证,代码如下:

# 导入第三方包
from sklearn import preprocessing
from sklearn import cluster
import numpy as np

# 选取建模的变量
predictors = ['Birth_Rate','Death_Rate']
# 变量的标准化处理
X = preprocessing.scale(Province[predictors]) X = pd.DataFrame(X)

# 构建空列表,用于保存不同参数组合下的结果
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.loc[df.n_clusters == 3, :]

如上表所示,如果需要将数据聚为3类,则得到如上几种参数组合,这里不妨选择eps为0.801,min_samples为3的参数值(因为该参数组合下的异常点个数比较合理)。接下来,利用如上所得的参数组合,构造密度聚类模型,实现原始数据集的聚类,代码如下:

# 导入第三方模块
import seaborn as sns

# 利用上述的参数组合值,重建密度聚类算法
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()

如上图所示,三角形、菱形和圆形所代表的点即为三个不同的簇,五角星所代表的点即为异常点,这个聚类效果还是非常不错的,对比建模之前的结论非常吻合。从上图可知,以北京、天津、上海为代表的省份属于低出生率和低死亡率类型广东、宁夏和新疆三个省份属于高出生率和低死亡率类型江苏、四川、湖北为代表的省份属于高出生率和高死亡率类型四个异常点中,黑龙江与辽宁比较相似,属于低出生率和高死亡率类型;山东省属于极高出生率和高死亡率的省份;西藏属于高出生率和低死亡率的省份,但它与广东、宁夏和新疆更为相似。

结语


OK,关于使用Python完成密度聚类的实战我们就分享到这里,在我的新书《从零开始学Python数据分析与挖掘》中,对密度聚类算法的落地也作了更多的讲解。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。

数据分析1480   

学习与分享,取长补短,关注小号!


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/TCt6mCOMC9
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/25801
 
627 次点击