基于c++实现dbscan聚类算法(代码片段)

Leonban Leonban     2022-11-04     243

关键词:

DBSCAN聚类算法进行了C++的实现,时间复杂度为O(n^2)。

 

1、数据点类型描述如下(DataPoint.h)

#include <vector> 
using namespace std;
const int DIME_NUM=2;        //数据维度为2,全局常量
 
//数据点类型
class DataPoint

private:
     unsigned long dpID;                //数据点ID
     double dimension[DIME_NUM];        //维度数据
     long clusterId;                    //所属聚类ID
     bool isKey;                        //是否核心对象
     bool visited;                    //是否已访问
     vector<unsigned long> arrivalPoints;    //领域数据点id列表
 public:
     DataPoint();                                                    //默认构造函数
     DataPoint(unsigned long dpID,double* dimension , bool isKey);    //构造函数
 
     unsigned long GetDpId();                //GetDpId方法
     void SetDpId(unsigned long dpID);        //SetDpId方法
     double* GetDimension();                    //GetDimension方法
     void SetDimension(double* dimension);    //SetDimension方法
     bool IsKey();                            //GetIsKey方法
     void SetKey(bool isKey);                //SetKey方法
     bool isVisited();                        //GetIsVisited方法
     void SetVisited(bool visited);            //SetIsVisited方法
     long GetClusterId();                    //GetClusterId方法
     void SetClusterId(long classId);        //SetClusterId方法
     vector<unsigned long>& GetArrivalPoints();    //GetArrivalPoints方法
 ;

2、对应实现(DataPoint.cpp)

#include "DataPoint.h"
 
  //默认构造函数
  DataPoint::DataPoint()
  
  
  
  //构造函数
  DataPoint::DataPoint(unsigned long dpID,double* dimension , bool isKey):isKey(isKey),dpID(dpID)
 
     //传递每维的维度数据
     for(int i=0; i<DIME_NUM;i++)
     
         this->dimension[i]=dimension[i];
     
 
 
 //设置维度数据
 void DataPoint::SetDimension(double* dimension)
 
     for(int i=0; i<DIME_NUM;i++)
     
         this->dimension[i]=dimension[i];
     
 
 
 //获取维度数据
 double* DataPoint::GetDimension()
 
     return this->dimension;
 
 
 //获取是否为核心对象
 bool DataPoint::IsKey()
 
     return this->isKey;
 
 
 //设置核心对象标志
 void DataPoint::SetKey(bool isKey)
 
     this->isKey = isKey;
 
 
 //获取DpId方法
 unsigned long DataPoint::GetDpId()
 
     return this->dpID;
 
 
 //设置DpId方法
 void DataPoint::SetDpId(unsigned long dpID)
 
     this->dpID = dpID;
 
 
 //GetIsVisited方法
 bool DataPoint::isVisited()
 
     return this->visited;
 
 
 
 //SetIsVisited方法
 void DataPoint::SetVisited( bool visited )
 
     this->visited = visited;
 
 
 //GetClusterId方法
 long DataPoint::GetClusterId()
 
     return this->clusterId;
 
 
 //SetClusterId方法
 void DataPoint::SetClusterId( long clusterId )
 
     this->clusterId = clusterId;
 
 
 //GetArrivalPoints方法
 vector<unsigned long>& DataPoint::GetArrivalPoints()
 
     return arrivalPoints;
 

3、DBSCAN算法类型描述(ClusterAnalysis.h)

#include <iostream>
#include <cmath>
#include "DataPoint.h"
#include<QVector>

using namespace std;
 //聚类分析类型
 class ClusterAnalysis
 
 private:
     vector<DataPoint> dadaSets;        //数据集合
     unsigned int dimNum;            //维度
     double radius;                    //半径
     unsigned int dataNum;            //数据数量
     unsigned int minPTs;            //邻域最小数据个数
     double GetDistance(DataPoint& dp1, DataPoint& dp2);                    //距离函数
     void SetArrivalPoints(DataPoint& dp);                                //设置数据点的领域点列表
     void KeyPointCluster( unsigned long i, unsigned long clusterId );    //对数据点领域内的点执行聚类操作
 public:
 
     ClusterAnalysis()                    //默认构造函数
     bool Init(QVector<QVector<QString>> Data, double radius, int minPTs);    //初始化操作
	 unsigned long DoDBSCANRecursive();            //DBSCAN递归算法
     bool WriteToFile(char* fileName);    //将聚类结果写入文件
	 bool ClusterAnalysis::GetScope(Scope* scope, QVector<QVector<QString>> Data);   //将已经过聚类算法处理的数据集合形成坐标范围
 ;

4、算法实现(ClusterAnalysis.cpp)

#include "ClusterAnalysis.h"
#include <fstream>
#include <iosfwd>
#include <math.h>
 
/*
 函数:聚类初始化操作
说明:将数据文件名,半径,领域最小数据个数信息写入聚类算法类,读取文件,把数据信息读入写进算法类数据集合中
参数:
QVector<QVector<QString>> Data;    //数据
double radius;    //半径
int minPTs;        //领域最小数据个数  
返回值: true;    */
bool ClusterAnalysis::Init(QVector<QVector<QString>> Data, double radius, int minPTs)

     this->radius = radius;        //设置半径
     this->minPTs = minPTs;        //设置领域最小数据个数
     this->dimNum = DIME_NUM;    //设置数据维度
 
     unsigned long i=0;            //数据个数统计
     //从Data读取POI信息,将POI信息写入POI列表中
     for (int k = 0; k < Data.size(); k++)
	 
         DataPoint tempDP;                //临时数据点对象
         double tempDimData[DIME_NUM];    //临时数据点维度信息
         for(int j=0; j<DIME_NUM; j++)    //读Data,读取每一维数据
         
			 tempDimData[j] = Data.at(k).at(j).toDouble();
         
         tempDP.SetDimension(tempDimData);    //将维度信息存入数据点对象内
 
 //char date[20]="";
 //char time[20]="";
         double type;    //无用信息
         //ifs >> date;
 //ifs >> time;    //无用信息读入
 
         tempDP.SetDpId(i);                    //将数据点对象ID设置为i
         tempDP.SetVisited(false);            //数据点对象isVisited设置为false
         tempDP.SetClusterId(-100);            //设置默认簇ID为-1
         dadaSets.push_back(tempDP);            //将对象压入数据集合容器
         i++;        //计数+1
     
     dataNum =i;            //设置数据对象集合大小为i
     for(unsigned long i=0; i<dataNum;i++)
     
         SetArrivalPoints(dadaSets[i]);            //计算数据点领域内对象
     
     return true;    //返回
 
 
 /*
 函数:将已经过聚类算法处理的数据集合写回文件
 说明:将已经过聚类结果写回文件
参数:
char* fileName;    //要写入的文件名
返回值: true    */
bool ClusterAnalysis::WriteToFile(char* fileName )

     ofstream of1(fileName);                                //初始化文件输出流
     for(unsigned long i=0; i<dataNum;i++)                //对处理过的每个数据点写入文件
     
        for(int d=0; d<DIME_NUM ; d++)                    //将维度信息写入文件
             of1<<dadaSets[i].GetDimension()[d]<<'\\t';
         of1 << dadaSets[i].GetClusterId() <<endl;        //将所属簇ID写入文件
     
     of1.close();    //关闭输出文件流
     return true;    //返回
 
 
 /*
 函数:设置数据点的领域点列表
说明:设置数据点的领域点列表
参数:
 返回值: true;    */
 void ClusterAnalysis::SetArrivalPoints(DataPoint& dp)
 
     for(unsigned long i=0; i<dataNum; i++)                //对每个数据点执行
     
         double distance =GetDistance(dadaSets[i], dp);    //获取与特定点之间的距离
         if(distance <= radius && i!=dp.GetDpId())        //若距离小于半径,并且特定点的id与dp的id不同执行
             dp.GetArrivalPoints().push_back(i);            //将特定点id压力dp的领域列表中
     
     if(dp.GetArrivalPoints().size() >= minPTs)            //若dp领域内数据点数据量> minPTs执行
     
         dp.SetKey(true);    //将dp核心对象标志位设为true
         return;                //返回
     
     dp.SetKey(false);    //若非核心对象,则将dp核心对象标志位设为false
 
 
  /*
 函数:执行聚类操作
 说明:执行聚类操作
 参数:
 返回值: true;    */
 unsigned long ClusterAnalysis::DoDBSCANRecursive()
 
     unsigned long clusterId=0;                        //聚类id计数,初始化为0
     for(unsigned long i=0; i<dataNum;i++)            //对每一个数据点执行
     
         DataPoint& dp=dadaSets[i];                    //取到第i个数据点对象
         if(!dp.isVisited() && dp.IsKey())            //若对象没被访问过,并且是核心对象执行
         
             dp.SetClusterId(clusterId);                //设置该对象所属簇ID为clusterId
             dp.SetVisited(true);                    //设置该对象已被访问过
             KeyPointCluster(i,clusterId);            //对该对象领域内点进行聚类
             clusterId++;                            //clusterId自增1
         
         //cout << "孤立点\\T" << i << endl;
     
 
//    cout <<"共聚类" <<clusterId<<"个"<< endl;        //算法完成后,输出聚类个数
     return clusterId;    //返回
 
 
 /*
 函数:对数据点领域内的点执行聚类操作
 说明:采用递归的方法,深度优先聚类数据
 参数:
 unsigned long dpID;            //数据点id
 unsigned long clusterId;    //数据点所属簇id
 返回值: void;    */
 void ClusterAnalysis::KeyPointCluster(unsigned long dpID, unsigned long clusterId )
 
     DataPoint& srcDp = dadaSets[dpID];        //获取数据点对象
     if(!srcDp.IsKey())    return;
     vector<unsigned long>& arrvalPoints = srcDp.GetArrivalPoints();        //获取对象领域内点ID列表
     for(unsigned long i=0; i<arrvalPoints.size(); i++)
     
        DataPoint& desDp = dadaSets[arrvalPoints[i]];    //获取领域内点数据点
         if(!desDp.isVisited())                            //若该对象没有被访问过执行
         
             //cout << "数据点\\t"<< desDp.GetDpId()<<"聚类ID为\\t" <<clusterId << endl;
             desDp.SetClusterId(clusterId);        //设置该对象所属簇的ID为clusterId,即将该对象吸入簇中
             desDp.SetVisited(true);                //设置该对象已被访问
             if(desDp.IsKey())                    //若该对象是核心对象
             
                 KeyPointCluster(desDp.GetDpId(),clusterId);    //递归地对该领域点数据的领域内的点执行聚类操作,采用深度优先方法
             
         
     
 
 
 //两数据点之间距离
 /*
 函数:获取两数据点之间距离
 说明:获取两数据点之间的欧式距离
 参数:
 DataPoint& dp1;        //数据点1
 DataPoint& dp2;        //数据点2
 返回值: double;    //两点之间的距离        */
 double ClusterAnalysis::GetDistance(DataPoint& dp1, DataPoint& dp2)
 
     double distance =0;        //初始化距离为0
     for(int i=0; i<DIME_NUM;i++)    //对数据每一维数据执行
     
         distance += pow(dp1.GetDimension()[i] - dp2.GetDimension()[i],2);    //距离+每一维差的平方
     
     return pow(distance,0.5);        //开方并返回距离
 


 /*
 函数:将已经过聚类算法处理的数据集合形成坐标范围
 参数:
 Scope* scopee;    //要写入的坐标范围
 返回值: true    */
 bool ClusterAnalysis::GetScope(Scope* scope, QVector<QVector<QString>> Data)
 
	 for (unsigned long i = 0; i<dataNum; i++)                //对处理过的每个数据点写入文件
	 
		 long clusterId = dadaSets[i].GetClusterId();
		 if (clusterId >= 0) 
		     if (scope[clusterId].flag == false) 
				 scope[clusterId].lon_max = dadaSets[i].GetDimension()[0];
				 scope[clusterId].lon_min = dadaSets[i].GetDimension()[0];
				 scope[clusterId].lat_max = dadaSets[i].GetDimension()[1];
				 scope[clusterId].lat_min = dadaSets[i].GetDimension()[1];
				 scope[clusterId].flag = true;
			 
			 else 
				 if (dadaSets[i].GetDimension()[0] > scope[clusterId].lon_max) 
					 scope[clusterId].lon_max = dadaSets[i].GetDimension()[0];
				 
				 if (dadaSets[i].GetDimension()[0] < scope[clusterId].lon_min) 
					 scope[clusterId].lon_min = dadaSets[i].GetDimension()[0];
				 
				 if (dadaSets[i].GetDimension()[1] > scope[clusterId].lat_max) 
					 scope[clusterId].lat_max = dadaSets[i].GetDimension()[1];
				 
				 if (dadaSets[i].GetDimension()[1] < scope[clusterId].lat_min) 
					 scope[clusterId].lat_min = dadaSets[i].GetDimension()[1];
				 
			 
			 int num = (scope[clusterId].num);
			 scope[clusterId].Datas[num] = i;
			 scope[clusterId].num++;
		 
	 

	 return true;    //返回
 

5、算法调用

首先需要对QVector<QVector<QString>> Data 源数据进行附值。

    #include "ClusterAnalysis.h"
    #include <cstdio>
     
     using namespace std;
     
     int main()
     
	     QVector<QVector<QString>> Data;            //首先给Data数据赋值(如经纬度数据)。
		 ClusterAnalysis myClusterAnalysis;                        //聚类算法对象声明
		 myClusterAnalysis.Init(Data, 3, 1);        //算法初始化操作,指定半径为3,领域内最小数据点个数为1,(在程序中已指定数据维度为2)
		 unsigned long clusterId = myClusterAnalysis.DoDBSCANRecursive();                    //执行聚类算法													
		 Scope* scope = new Scope[clusterId + 1];
		 myClusterAnalysis.GetScope(scope, Data);
         return 0;            //返回
     

聚类算法之dbscan(代码片段)

DBSCAN聚类算法1.DBSCAN算法基本概念DBSCAN是一种典型的基于密度的聚类算法,基于一组邻域(ϵ,MinPts)(\\epsilon,MinPts)(ϵ,MinPts)来描述样本集的紧密程度。其中ϵ\\epsilonϵ描述了某一样本的邻域距离阈值,MinPtsMinPtsMinPts描述了某一... 查看详情

⭐k-means和dbscan聚类算法——理论结合代码的实现(代码片段)

...部法则优化k2.2.3.2轮廓系数2.2.4MiniBatchKMeans三、DBSCAN(基于密度)3.1基本概念3.2凸数据集3. 查看详情

⭐k-means和dbscan聚类算法——理论结合代码的实现(代码片段)

...部法则优化k2.2.3.2轮廓系数2.2.4MiniBatchKMeans三、DBSCAN(基于密度)3.1基本概念3.2凸数据集3. 查看详情

dbscan聚类算法的实现(代码片段)

DBSCAN聚类算法的实现1.作者介绍2.关于理论方面的知识介绍2.1DBSCAN算法介绍2.2鸢尾花数据集介绍3.实验过程3.1实验代码3.2实现过程3.3实验结果4.参考文献1.作者介绍刘鹏程,男,西安工程大学电子信息学院,202... 查看详情

聚类算法之dbscan(java实现)

DBScan是一种基于密度的聚类算法,它有一个核心点的概念:如果一个点,在距它Eps的范围内有不少于MinPts个点,则该点就是核心点。核心和它Eps范围内的邻居形成一个簇。在一个簇内如果出现多个点都是核心点,则以这些核心点... 查看详情

密度聚类算法dbscan实战及可视化分析(代码片段)

密度聚类算法DBSCAN实战及可视化分析目录密度聚类算法DBSCAN实战及可视化分析DBSCAN实战及聚类效果可视化构建分类算法获得预测推理能力DBSCAN实战及聚类效果可视化DBSCAN算法将数据集定义为高密度的连续区域,下面是它的工... 查看详情

dbscan

[+]一基于密度的聚类算法的概述二DBSCAN算法的原理基本概念算法流程三实验仿真参考文献一、基于密度的聚类算法的概述  最近在Science上的一篇基于密度的聚类算法《Clusteringbyfastsearchandfindofdensitypeaks》引起了大家的关注(在... 查看详情

常用聚类算法dbscan算法

...N(Density-BasedSpatialClusteringofApplicationswithNoise,具有噪声的基于密度的聚类方法)是一种基于密度的空间聚类算法。该算法将具有足够密度的区域划分为簇,并在具有噪声的空间数据库中发现任意形 查看详情

机器学习sklearn无监督学习聚类算法dbscan(代码片段)

importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.clusterimportDBSCANfromsklearn.clusterimportKMeansfromsklearnimportdatasets#生成数据x1,y1=datasets.make_circles(n_samples=2000,factor=0.5 查看详情

机器学习sklearn无监督学习聚类算法dbscan(代码片段)

importnumpyasnpimportmatplotlib.pyplotaspltfromsklearn.clusterimportDBSCANfromsklearn.clusterimportKMeansfromsklearnimportdatasets#生成数据x1,y1=datasets.make_circles(n_samples=2000,factor=0.5 查看详情

weka算法clusterers-dbscan源代码分析

假设说世界上仅仅能存在一种基于密度的聚类算法的话。那么它必须是DBSCAN(Density-basedspatialclusteringofapplicationswithnoise)。DBSCAN作为基于密度聚类算法的典型,相对于Kmeans,最大长处是能够自己决定聚类数量。同一时候能够过滤... 查看详情

备战数学建模44-聚类模型(攻坚站8)(代码片段)

...:分类是已知类别的,聚类未知。常用的聚类有基于距离的:包括K-means和系统聚类等,基于密度的DASCAN算法等。目录一、Keans和K-means++算法1.1、K-means算法1.2、K-means++算法 二、系统(层次)聚类2.1、系统... 查看详情

dbscan算法简介

...nswithnoise)是MartinEster,Hans-PeterKriegel等人于1996年提出的一种基于密度的聚类方法,聚类前不需要预先指定聚类的个数,生成的簇的个数不定&#x 查看详情

dbscan聚类算法

...CAN(Density-BasedSpatialClusteringofApplicationswithNoise,具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法,和K-Means,BIRCH这些一般只适用于凸样本集的聚类相比,DBSCAN既可以适用于凸样本集,也可以适用于非凸样本集。DBSCAN... 查看详情

11-聚类算法(kmeans/dbscan/agg)(算法)(代码片段)

...kmeans.fit(data.iloc[:,1:])#无监督,只需要给数据X就可以DBSCAN算法是以某点为起始点,如果到该点距离的附近点的数量达到一定数量就可以进入该集合,类似传销。dbscan=DBSCAN(eps=0.2,min_samples=3)dbscan.fit(X)agg算法是先找距离最... 查看详情

kmeans和dbscans将相邻的轮廓聚类(代码片段)

问题:如何使用传统的图像处理方法将相邻的轮廓聚类,同时轮廓变成规则矩形,大的矩形框里的矩形框消失。 ​聚类算法: K-Means算法k均值聚类算法(k-meansclusteringalgorithm)是一种迭代求解的聚类分析... 查看详情

聚类算法(k-means&agnes&dbscan)(代码片段)

一、聚类算法基本概念1.定义:聚类就是按照某个特定标准(如距离准则)把一个数据集分割成不同的类或簇,使得同一个簇内的数据对象的相似性尽可能大。即聚类后同一类的数据尽可能聚集到一起,不同数据尽量分... 查看详情

空间聚类算法简述

...聚类算法主要包括四大类:(1)给予划分的聚类;(2)基于层次的聚类;(3)基于密度的聚类;(4)基于网格的聚类。时空数据聚类算法是空间数据聚类算法的验身,它将时许维度纳入聚类计算中。1.1基于划分的空间聚类算... 查看详情