基于C++实现DBSCAN聚类算法
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; //数据点IDdouble dimension[DIME_NUM]; //维度数据long clusterId; //所属聚类IDbool 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设置为itempDP.SetVisited(false); //数据点对象isVisited设置为falsetempDP.SetClusterId(-100); //设置默认簇ID为-1dadaSets.push_back(tempDP); //将对象压入数据集合容器i++; //计数+1}dataNum =i; //设置数据对象集合大小为ifor(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核心对象标志位设为truereturn; //返回}dp.SetKey(false); //若非核心对象,则将dp核心对象标志位设为false}/*函数:执行聚类操作说明:执行聚类操作参数:返回值: true; */unsigned long ClusterAnalysis::DoDBSCANRecursive(){unsigned long clusterId=0; //聚类id计数,初始化为0for(unsigned long i=0; i<dataNum;i++) //对每一个数据点执行{DataPoint& dp=dadaSets[i]; //取到第i个数据点对象if(!dp.isVisited() && dp.IsKey()) //若对象没被访问过,并且是核心对象执行{dp.SetClusterId(clusterId); //设置该对象所属簇ID为clusterIddp.SetVisited(true); //设置该对象已被访问过KeyPointCluster(i,clusterId); //对该对象领域内点进行聚类clusterId++; //clusterId自增1}//cout << "孤立点\T" << i << endl;}// cout <<"共聚类" <<clusterId<<"个"<< endl; //算法完成后,输出聚类个数return clusterId; //返回}/*函数:对数据点领域内的点执行聚类操作说明:采用递归的方法,深度优先聚类数据参数:unsigned long dpID; //数据点idunsigned 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; //数据点1DataPoint& dp2; //数据点2返回值: double; //两点之间的距离 */double ClusterAnalysis::GetDistance(DataPoint& dp1, DataPoint& dp2){double distance =0; //初始化距离为0for(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; //返回}
基于C++实现DBSCAN聚类算法相关推荐
- 基于GPU的K-Means聚类算法
聚类是信息检索.数据挖掘中的一类重要技术,是分析数据并从中发现有用信息的一种有效手段.它将数据对象分组成为多个类或簇,使得在同一个簇中的对象之间具有较高的相似度,而不同簇中的对象差别很大.作为统计学的 ...
- dbscan聚类算法matlab_密度聚类DBSCAN、HDBSCAN(转)
# 密度聚类DBSCAN.HDBSCAN DBSCAN DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声 ...
- dbscan聚类算法_一种视频人群流的轨迹聚类方法
tags: KLT光流法,K-means聚类算法,DBSCAN聚类算法 方法简介 运动轨迹是一种在视频场景中捕捉复杂时间动态的有效方法.因此,我们将人流分割问题转化为一个轨迹提取和聚类任务.该方法分为 ...
- DBSCAN聚类算法原理及图解
DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法,和K-M ...
- K-means与DBSCAN聚类算法
K-means与DBSCAN聚类算法 前言:目前数据聚类方法大体上可以分为划分式聚类方法(Partition-based Methods).基于密度的聚类方法(Density-based method ...
- 毫米波雷达点云 DBSCAN聚类算法
毫米雷达点云 DBSCAN聚类算法 聚类的目的 聚类算法分类 原型聚类 层次聚类 密度聚类 DBSCAN聚类算法原理 相关定义 算法流程以及伪代码 DBSCAN算法优缺点 DBSCAN参数选择 聚类衡 ...
- dbscan算法_如何掌握用于机器学习的流行DBSCAN聚类算法
总览 DBSCAN聚类是一种针对无监督学习问题而被低估但非常有用的聚类算法 了解DBSCAN集群如何工作,为什么要学习以及如何在Python中实现DBSCAN集群 介绍 掌握无监督学习为数据科学家开辟 ...
- DBSCAN聚类算法——机器学习(理论+图解+python代码)
一.前言 二.DBSCAN聚类算法 三.参数选择 四.DBSCAN算法迭代可视化展示 五.常用的评估方法:轮廓系数 六.用Python实现DBSCAN聚类算法 一.前言 去年学聚类算法的R语言的时候, ...
- dbscan算法c语言实现,用C++实现DBSCAN聚类算法
这几天由于工作需要,对DBSCAN聚类算法进行了C++的实现.时间复杂度O(n^2),主要花在算每个点领域内的点上.算法很简单,现共享大家参考,也希望有更多交流. 数据点类型描述如下: 复制代码 代码 ...
- WKmeans一种基于特征权重的聚类算法
1 引例 在前面两篇文章中,我们首先介绍了KmeansKmeansKmeans聚类算法的原理:然后又介绍了一种基于KmeansKmeansKmeans进行改进的Kmeans++Kmeans++Kmea ...
最新文章
- python代码基础题-Python初学者福利 完整试题附答案 干货(收藏篇)
- IDEA报错Web server failed to start. Port 8080 was already in use的解决方法
- 几位阿里朋友重写的Java并发编程,牛逼了
- SpringBoot使用@Cacheable实现最简单的Redis缓存
- 一个Demo学会用Android兼容包新控件
- 从数组到 HashMap 之算法解释
- RedHat Linux 加入域
- C#中网络编程异步操作方法与 粘包和分包问题
- java gson 解析json字符串_JSON 之GSON 解析
- 【C++】【GADL】读取栅格数据获取信息
- Notepad工具json格式转换
- SQL SERVER 修改字段长度
- 美团2015年校园招聘部分笔试题
- Springboot整合ES8(Java API Client)
- 应用场景是什么?怎样判断、描述一个产品的应用场景?
- Instagram 账号被封如何申诉拿回账号?ins账号解封经验分享
- 当代大学生的生活痛点
- John Ripper的模式和配置
- 南琼考试系统服务器怎么填,南琼考试系统N5
- 使用Mybatis联表查询的几种方式