IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> python实现DBSCAN聚类 -> 正文阅读

[人工智能]python实现DBSCAN聚类

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

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

算法实战

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

在密度聚类算法的实战部分,我们将使用国内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()

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

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, :])

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

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

该算法完整代码如下:

# 导入模块
# 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()

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

代码中遇到的语法问题

一、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)

输出结果为:

加上set()后

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

?输出结果为:,可以看出去除了重复元素,但是变得无序。

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

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])  # 找频数最高的键

输出结果为:

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) 

输出结果为:,最后得到的是1,0,2,-1分别出现的次数的一个列表。

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))

?输出结果为:

?四、df.loc的用法

Pandas.DataFrame.loc函数用法大全

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-04-26 11:41:49  更:2022-04-26 11:43:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:31:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码