【机器学习】密度聚类:从底层手写实现DBSCAN

【机器学习】Building-DBSCAN-from-Scratch

  • 概念
  • 代码
    • 数据导入
    • 实现DBSCAN
    • 使用样例及其可视化
  • 补充资料

概念

DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种基于密度的空间聚类算法。该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形状的簇,它将簇定义为密度相连的点的最大集合。

该算法的核心概念是识别位于高密度区域的样本点,并将它们划分为簇。以图中的点A为例,我们观察到A点周围有较高的点密度。根据DBSCAN算法的特定参数——即邻域半径(Epsilon)和最小点数(MinPts)——我们可以确定一个点是否为核心点、边界点或离群点。

在这里插入图片描述

在此过程中,算法首先随机选择一个样本点(如A点)并围绕其绘制一个圆,其半径等于邻域半径。如果在这个圆内的样本点数量达到或超过MinPts的阈值,则该点被视为核心点,并且圆心会移动到圆内的另一个样本点,继续探索相邻区域。这个过程持续进行,直到没有更多的点可以加入到当前簇中。此时,圆内最后一个样本点被视为边界点,如B或C。而那些未能被纳入任何簇的点,如N,被视为离群点。

通过这种方式,DBSCAN算法有效地将样本空间中距离相近的点聚合在一起,形成不同的簇,同时识别并排除噪声或异常值。这种基于密度的聚类方法特别适合于处理具有复杂结构或不规则形状的数据集。

在这里插入图片描述

代码

数据导入

from sklearn.datasets import load_iris  # 导入数据集iris
import matplotlib.pyplot as plt  # 导入绘图库
import numpy as np  # 导入numpy库
# 加载Iris数据集
iris = load_iris()
X = iris.data  # 获得其特征向量,150*4

实现DBSCAN

在OurDBSCAN类中,我们首先通过初始化函数设置了邻域半径eps和最小样本数min_samples,这两个参数是确定簇的关键。在fit方法中,对输入数据集X的每个点进行遍历和分类处理。

算法开始时,所有点都标记为未分类。接着,对每个点,先检查其状态,如果已经分类则跳过,否则通过_find_neighbors方法找出该点的所有邻居。这一步骤涉及计算点与其他所有点之间的欧氏距离,判断是否在设定的邻域半径内。如果一个点的邻居数少于min_samples,则将其标记为噪声。

当一个点有足够多的邻居被确定为核心点后,算法会创建一个新的簇,并通过迭代地探索该点的邻居来扩展这个簇。在此过程中,每个新发现的点都会被检查是否也是核心点,如果是,它的邻居也会被加入到当前簇中。这种方式使得DBSCAN能够根据密度将数据集中的点聚合成多个簇,同时识别和剔除噪声点,有效应对具有不规则形状或包含噪声和异常值的数据集。

class OurDBSCAN:
    def __init__(self, eps, min_samples):
        """
        初始化DBSCAN对象。

        参数:
            eps (float): 邻域的半径。
            min_samples (int): 核心点的邻域中的最小样本数。
        """
        self.eps = eps  # 邻域的半径
        self.min_samples = min_samples  # 核心点的最小样本数
        self.labels_ = None  # 簇标签

    def fit(self, X):
        """
        将DBSCAN模型拟合到输入数据。

        参数:
            X (array-like): 输入数据。

        返回:
            None
        """
        # 将所有点标记为-1(未分类)
        labels = -1 * np.ones(X.shape[0])  # -1表示未分类

        # 簇ID
        cluster_id = 0

        for i in range(X.shape[0]):  # 遍历所有点
            
            # 如果该点已被访问过,则跳过
            if labels[i] != -1:
                continue

            # 找到当前点的所有邻居
            neighbors = self._find_neighbors(i, X)

            # 如果邻居数小于min_samples,则标记为噪声并继续
            if len(neighbors) < self.min_samples:
                labels[i] = -2  # -2表示噪声
                continue

            # 否则,开始一个新的簇
            labels[i] = cluster_id

            # 找到当前簇的所有邻居
            seeds = set(neighbors)  # 邻居集合
            seeds.remove(i)  # 移除当前点

            while seeds:  # 只要种子集合不为空
                # 取出一个邻居
                current_point = seeds.pop()

                # 如果是噪声,则将其标记为当前簇
                if labels[current_point] == -2:
                    labels[current_point] = cluster_id

                # 如果已经处理过,则跳过
                if labels[current_point] != -1:
                    continue

                # 否则,将其标记为当前簇
                labels[current_point] = cluster_id

                # 找到当前点的所有邻居
                current_neighbors = self._find_neighbors(current_point, X)

                # 如果当前点是核心点,则将其邻居添加到种子集合中
                if len(current_neighbors) >= self.min_samples:
                    seeds.update(current_neighbors)

            # 移动到下一个簇
            cluster_id += 1

        self.labels_ = labels  # 保存簇标签
        

    def _find_neighbors(self, point_idx, X):
        """
        找到给定点的邻居。

        参数:
            point_idx (int): 点的索引。
            X (array-like): 输入数据。

        返回:
            neighbors (list): 邻居的索引。
        """
        neighbors = []
        for i, point in enumerate(X):  # 遍历所有点
            if np.linalg.norm(X[point_idx] - point) <= self.eps:  # 计算距离
                neighbors.append(i)
        return neighbors

使用样例及其可视化

# 使用手动实现的 DBSCAN,不使用 NearestNeighbors
manual_dbscan_nn = OurDBSCAN(eps=0.5, min_samples=5)
manual_dbscan_nn.fit(X)
# 创建一个图形和子图
fig, axs = plt.subplots(2, 3, figsize=(15, 10))

# 组合特征以创建散点图
feature_combinations = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
feature_names = iris.feature_names

for i, (fi, fj) in enumerate(feature_combinations):
    ax = axs[i//3, i % 3]
    ax.scatter(X[:, fi], X[:, fj], c=manual_dbscan_nn.labels_, cmap='viridis',
               marker='o', edgecolor='k', s=50)
    ax.set_xlabel(feature_names[fi])
    ax.set_ylabel(feature_names[fj])
    ax.set_title(
        f'DBSCAN Clustering with {feature_names[fi]} vs {feature_names[fj]}')

plt.tight_layout()
plt.show()

在这里插入图片描述
在IRIS数据集中,每个样本都有四个特征:花萼长度(sepal length)、花萼宽度(sepal width)、花瓣长度(petal length)和花瓣宽度(petal width),所有的这些特征都以厘米为单位进行测量。在第一行的图表中,我们可以看到花萼长度与花萼宽度、花瓣长度和花瓣宽度的聚类关系。在第二行,展示的是花萼宽度与花瓣长度、花瓣宽度的聚类效果,以及花瓣长度与花瓣宽度的聚类情况。

通过DBSCAN算法的密度聚类特性,我们可以看到在密度较高的区域形成了聚类簇,而在密度较低的区域,点则被标记为噪声点或者位于不同簇的边界。

补充资料

一个有趣的DBSCAN可视化网站:
https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/258796.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSharp中Blazor初体验

Blazor 是一个由微软开发的开源 Web 框架&#xff0c;用于构建富客户端 Web 应用程序使用 C# 语言和 .NET 平台。Blazor 允许开发人员使用 C# 语言来编写前端 Web 应用程序&#xff0c;而不需要像传统的 JavaScript 框架&#xff08;如 Angular、React 或 Vue.js&#xff09;那…

代码随想录算法训练营第二十一天 | 二叉树众数、公共祖先

目录 力扣题目 力扣题目记录 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 普通二叉树 搜索二叉树 236. 二叉树的最近公共祖先 总结 总结 力扣题目 用时&#xff1a;2h 1、530.二叉搜索树的最小绝对差 2、501.二叉搜索树中的众数 3、236. 二叉树的最近公共…

02 ModBus TCP

目录 一、ModBus TCP 一帧数据格式 二、0x01 读线圈状态 三、0x03读保持寄存器 四、0x05写单个线圈 五、0x06 写单个寄存器 六、0x0f写多个线圈 七、0x10&#xff1a;写多个保持寄存器 八、通信过程 九、不同modbus通信模式的应用场景 一、ModBus TCP 一帧数据格式 其…

队列(C语言版)

一.队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有 先进先出 FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为 队尾 出队列&#xff1a;进行删除操作的一端称为…

【大数据面试】Flink面试题附答案

目录 ✅Flink介绍、特点、应用场景 ✅Flink与Spark Streaming的区别 ✅Flink有哪些部署模式 ✅Flink架构 ✅怎么设置并行度&#xff1f; ✅什么是算子链&#xff1f; ✅什么是任务槽&#xff08;Task Slots&#xff09;&#xff1f; ✅任务槽和并行度的关系 ✅Flink作…

自动化测试入门 —— 自动化测试概论

整篇论述总的来讲会很长&#xff0c;从自动化的思维、模型、工具&#xff0c;到各层次的自动化测试技术、测试框架、测试平台&#xff0c;包括面向未来的自动化技术都将涉及&#xff0c;因此打算拆成几个部分去写。此外&#xff0c;由于涉及的范围比较广泛&#xff0c;部分内容…

C++内存布局(二)

在《C内存布局(一)》 中&#xff0c;我们介绍了C内存布局的基本知识&#xff0c;本篇我们仍着重探讨C类的内存布局&#xff0c;尤其是 多重继承、钻石继承&#xff08;菱形继承&#xff09;场景下的虚函数表的情况。 一、多重继承 1.1 示例 class A { public:virtual void d…

LabVIEW软件模拟氢燃料电池在车辆中的应用

LabVIEW软件模拟氢燃料电池在车辆中的应用 在追求可持续能源的时代&#xff0c;氢燃料电池在绿色经济中扮演着关键角色。本研究通过LabVIEW软件模拟和评估了氢燃料电池在车辆应用中的性能和效率。LabVIEW作为一个强大的模拟工具&#xff0c;能够动态模拟氢燃料电池系统在不同条…

js键盘事件keydown事件,防止重复触发,组合键的配合使用

js键盘事件keydown事件&#xff0c;防止重复触发 键盘事件类型主要有三种&#xff1a; keydown 、keypress(不建议使用&#xff0c;部分浏览器已放弃)和 keyup 。 添加普通键盘keydown事件 // 监听键盘按下事件document.addEventListener(keydown, function(event) {// 输出按…

3 python基本语法 - Dict 字典

Python 中字典&#xff08;dict&#xff09;是一种无序的、可变的序列&#xff0c;它的元素以“键值对&#xff08;key-value&#xff09;”的形式存储。相对地&#xff0c;列表&#xff08;list&#xff09;和元组&#xff08;tuple&#xff09;都是有序的序列&#xff0c;它们…

23、Web攻防——Python考点CTF与CMS-SSTI模板注入PYC反编译

文章目录 一、PYC文件二、SSTI 一、PYC文件 pyc文件&#xff1a;python文件编译后生成的字节码文件&#xff08;byte code&#xff09;&#xff0c;pyc文件经过python解释器最终会生成机器码运行。因此pyc文件是可以跨平台部署的&#xff0c;类似java的.class文件&#xff0c;…

Vue-图片懒加载

实现图片懒加载可以使用vue-lazyload插件 npm 链接&#xff1a;vue-lazyload - npm (npmjs.com) 使用方法&#xff1a; 1. 安装vue-lazyload npm i vue-lazyload npm i vue-lazyload1.3.3 // 如果是vue2就需要安装1.3.3版本 2. 引入vue-lazyload并使用 可以在使用该插…

软件企业在什么情况下需要找第三方软件测试机构?如何收费?

近年来&#xff0c;随着软件行业的迅猛发展&#xff0c;软件企业对软件测试的需求也越来越大。为了保证软件的质量和稳定性&#xff0c;许多企业选择寻找第三方软件测试机构来进行软件测试。第三方软件测试机构是独立于软件开发企业的专业机构&#xff0c;主要从事软件测试和质…

每日一题 2828. 判别首字母缩略词(简单)

简单题&#xff0c;就不多写了 class Solution:def isAcronym(self, words: List[str], s: str) -> bool:if len(words) ! len(s):return Falsefor i in range(len(words)):if words[i][0] ! s[i]:return Falsereturn True

栈(stack)

栈&#xff08;stack&#xff09;是一种用于存储数据的简单数据结构&#xff0c;与链表和顺序表很相似&#xff0c;最大的区别在于数据的存取操作。栈的插入和删除操作只允许在一端执行&#xff0c;因此把允许操作的一端称为栈顶&#xff0c;不允许操作的称为栈底。插入元素称为…

轻度听力损失的儿童需要早期干预吗?

一些宝宝在做听力筛查时总是不通过&#xff0c;进一步听力诊断发现宝宝有轻度的听力损失&#xff0c;刚知道这个消息时&#xff0c;家长可担心了&#xff0c;总想着宝宝是不是听不到啊&#xff1f;但是一段时间后&#xff0c;有些家长又会忽略宝宝的听力问题&#xff0c;因为部…

7款创意性前端源码特效资源分享(附在线预览效果)

分享7款非常不错炫酷的前端特效源码 其中包含css动画特效、js原生特效、svg特效等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源 CSS绘制iPhone 14带动态岛 纯CSS绘制iPhone 14带动态岛模型 运行初始化时还附带出场动画 …

防冻水表是什么?

防冻水表是一种特殊类型的水表&#xff0c;它主要用于防止水管和设备在寒冷的冬季中受到冻结和损坏的情况。在冷却系统中使用防冻水表可以有效地监测和控制液体的温度&#xff0c;从而保护系统的正常运行。 防冻水表通常由温度传感器、控制器和显示器组成。温度传感器负责测量液…

阿里云k8s集群搭建

文章目录 一、安装前准备1.环境2.k8s集群规划 二、k8s 安装1. centos基础设置2. docker 安装3. k8s安装3.1 添加阿里云 yum 源3.2 安装 kubeadm、kubelet、kubectl3.3 部署 Kubernetes Master3.4 加入 Kubernetes Node3.5 部署 CNI 网络插件3.6 测试 kubernetes 集群 一、安装前…