python实现DBSCAN聚类

该博客配套代码、数据及PPT见百度网盘

链接:https://pan.baidu.com/s/1j1iWnhXmQiAnQ7VnfsCIrQ
提取码:6666

算法实战

数据为31个省份的出生率和死亡率,文件名为Province.xlsx

python实现DBSCAN聚类

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

import pandas as pd
import matplotlib.pyplot as plt

读取外部数据
Province = pd.read_excel(r'D:\myPythonFiles\python数据分析\TextbookCode\密度聚类\Province.xlsx')
Province.head()  # 显示表格的前五行
绘制出生率与死亡率散点图
plt.scatter(Province.Birth_Rate, Province.Death_Rate)  # Birth_Rate作为x Death_Rate作为y
添加轴标签
plt.xlabel('Birth_Rate')
plt.ylabel('Death_Rate')
显示图形
plt.show()

python实现DBSCAN聚类
import pandas as pd
import matplotlib.pyplot as plt
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])
        # 异常点的个数
        outlines = 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, 'outlines': outlines, 'stats': stats})

将迭代后的结果存储到数据框中
df = pd.DataFrame(res)
根据条件筛选合理的参数组合
print(df.loc[df.n_clusters == 3, :])

我们通过把不同参数组合下的结果保存下来,寻找较为合理的聚类结果。

python实现DBSCAN聚类

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

该算法完整代码如下:

导入模块
coding=utf-8
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import preprocessing  # 用于变量的标准化处理
from sklearn import cluster
import numpy as np
import seaborn as sns  # 用于绘制聚类的效果散点图

用于DataFrame显示所有列
pd.set_option('display.max_columns', None)
显示所有行
pd.set_option('display.max_rows', None)

用于最后输出的图形汉字显示正常
plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

读取外部数据
Province = pd.read_excel(r'D:\myPythonFiles\python数据分析\TextbookCode\密度聚类\Province.xlsx')
Province.head()  # 显示表格的前五行
绘制出生率与死亡率散点图
plt.scatter(Province.Birth_Rate, Province.Death_Rate)  # Birth_Rate作为x Death_Rate作为y
添加轴标签
plt.xlabel('Birth_Rate')
plt.ylabel('Death_Rate')
显示图形
plt.show()

选取建模的变量
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])
        # 异常点的个数
        outlines = 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, 'outlines': outlines, 'stats': stats})

将迭代后的结果存储到数据框中
df = pd.DataFrame(res)
根据条件筛选合理的参数组合
print(df.loc[df.n_clusters == 3, :])

利用上述的参数组合值,重建密度聚类算法
dbscan = cluster.DBSCAN(eps=0.801, min_samples=3)
模型拟合
dbscan.fit(X)
Province['dbscan_label'] = dbscan.labels_
绘制聚类的效果散点图  hue用于分类
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()

python实现DBSCAN聚类

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

代码中遇到的语法问题

一、for i in set()来迭代遍历去除列表中的重复元素

n_clusters = len([i for i in set(dbscan.labels_) if i != -1])

这句用来统计各参数组合下的聚类个数,对于for in i set() 的用法看下面的例子

list1 = [-1, 111, 111, 222, 777, 777, 333, 444, 555, 666]
for i in list1:
    print(i)

python实现DBSCAN聚类

加上set()后

list1 = [-1, 111, 111, 222, 777, 777, 333, 444, 555, 666]
for i in set(list1):
    print(i)

python实现DBSCAN聚类

那么我们就可以理解下面这个语句。

list1 = [-1, 111, 111, 222, 777, 777, 333, 444, 555, 666]
print(len([i for i in set(list1) if i != -1]))

这个语句用来打印出 list1 列表去除了重复元素和-1之后的长度,输出为7。

二、np.where的用法

outlines = np.sum(np.where(dbscan.labels_ == -1, 1, 0))

上面这行代码用来统计不同参数组合下的异常点的个数。

np.where有两种用法
1.np.where(condition,x,y) 当where内有三个参数时,第一个参数表示条件,当条件成立时where方法返回x,当条件不成立时where返回y。
2.np.where(condition) 当where内只有一个参数时,那个参数表示条件,当条件成立时,where返回的是每个符合condition条件元素的坐标,返回的是以元组的形式。

上面这行代码其实就是用法一,dbscan.labels_ == -1是判断条件,当聚类的标签为-1时返回1,否则返回0。最后用np.sum()函数求和就可以得到异常点的个数。

接着我们看下用法二的代码示例:

a = np.array([1, 3, 4, 6, 8, 9])
只有一个参数表示条件的时候
print(np.where(a > 5))

输出为(array([3, 4, 5], dtype=int64),)

注意打印的是数组的下标,并非是数组的元素。

三、pd.Series()的用法

 stats = str(pd.Series([i for i in dbscan.labels_ if i != -1]).value_counts().values)

上面这句是用来统计不同参数组合下的每个簇的样本个数

在pandas里面常用value_counts确认数据出现的频率。看下面的一个例子

ss = pd.Series([-1, 0, 1, 2, 1, 0, 2, 0, 1, 1])
print(ss.value_counts())
print(ss.value_counts().index[0])  # 找频数最高的键

python实现DBSCAN聚类
import pandas as pd

ss = pd.Series([-1, 0, 1, 2, 1, 0, 2, 0, 1, 1])
print(ss.value_counts())
print(ss.value_counts().values)

python实现DBSCAN聚类
import pandas as pd

labels = [-1, 0, 1, 2, 1, 0, 2, 0, 1, 1]
print(str(pd.Series([i for i in labels if i != -1]).value_counts().values))

python实现DBSCAN聚类

四、df.loc的用法

Pandas.DataFrame.loc函数用法大全

Original: https://blog.csdn.net/A1010574609/article/details/124398476
Author: 啃西瓜的小煤球
Title: python实现DBSCAN聚类

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/549532/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球