DBSCAN聚類算法進行了C++的實現(xiàn),,時間復(fù)雜度為O(n^2)。
1,、數(shù)據(jù)點類型描述如下(DataPoint.h)
const int DIME_NUM=2; //數(shù)據(jù)維度為2,全局常量 unsigned long dpID; //數(shù)據(jù)點ID double dimension[DIME_NUM]; //維度數(shù)據(jù) vector<unsigned long> arrivalPoints; //領(lǐng)域數(shù)據(jù)點id列表 DataPoint(); //默認構(gòu)造函數(shù) DataPoint(unsigned long dpID,double* dimension , bool isKey); //構(gòu)造函數(shù) 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,、對應(yīng)實現(xiàn)(DataPoint.cpp)
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() void DataPoint::SetKey(bool isKey) unsigned long DataPoint::GetDpId() void DataPoint::SetDpId(unsigned long dpID) bool DataPoint::isVisited() void DataPoint::SetVisited( bool visited ) long DataPoint::GetClusterId() void DataPoint::SetClusterId( long clusterId ) this->clusterId = clusterId; vector<unsigned long>& DataPoint::GetArrivalPoints()
3,、DBSCAN算法類型描述(ClusterAnalysis.h)
vector<DataPoint> dadaSets; //數(shù)據(jù)集合 unsigned int dimNum; //維度 unsigned int dataNum; //數(shù)據(jù)數(shù)量 unsigned int minPTs; //鄰域最小數(shù)據(jù)個數(shù) double GetDistance(DataPoint& dp1, DataPoint& dp2); //距離函數(shù) void SetArrivalPoints(DataPoint& dp); //設(shè)置數(shù)據(jù)點的領(lǐng)域點列表 void KeyPointCluster( unsigned long i, unsigned long clusterId ); //對數(shù)據(jù)點領(lǐng)域內(nèi)的點執(zhí)行聚類操作 ClusterAnalysis(){} //默認構(gòu)造函數(shù) bool Init(QVector<QVector<QString>> Data, double radius, int minPTs); //初始化操作 unsigned long DoDBSCANRecursive(); //DBSCAN遞歸算法 bool WriteToFile(char* fileName); //將聚類結(jié)果寫入文件
4、算法實現(xiàn)(ClusterAnalysis.cpp)
#include 'ClusterAnalysis.h' 說明:將數(shù)據(jù)文件名,,半徑,,領(lǐng)域最小數(shù)據(jù)個數(shù)信息寫入聚類算法類,,讀取文件,把數(shù)據(jù)信息讀入寫進算法類數(shù)據(jù)集合中 QVector<QVector<QString>> Data; //數(shù)據(jù) int minPTs; //領(lǐng)域最小數(shù)據(jù)個數(shù) bool ClusterAnalysis::Init(char* fileName, double radius, int minPTs) this->radius = radius; //設(shè)置半徑 this->minPTs = minPTs; //設(shè)置領(lǐng)域最小數(shù)據(jù)個數(shù) this->dimNum = DIME_NUM; //設(shè)置數(shù)據(jù)維度 ifstream ifs(fileName); //打開文件 if (! ifs.is_open()) //若文件已經(jīng)被打開,,報錯誤信息 cout << 'Error opening file'; //輸出錯誤信息 unsigned long i=0; //數(shù)據(jù)個數(shù)統(tǒng)計 while (! ifs.eof() ) //從文件中讀取POI信息,,將POI信息寫入POI列表中 DataPoint tempDP; //臨時數(shù)據(jù)點對象 double tempDimData[DIME_NUM]; //臨時數(shù)據(jù)點維度信息 for(int j=0; j<DIME_NUM; j++) //讀文件,讀取每一維數(shù)據(jù) tempDP.SetDimension(tempDimData); //將維度信息存入數(shù)據(jù)點對象內(nèi) tempDP.SetDpId(i); //將數(shù)據(jù)點對象ID設(shè)置為i tempDP.SetVisited(false); //數(shù)據(jù)點對象isVisited設(shè)置為false tempDP.SetClusterId(-1); //設(shè)置默認簇ID為-1 dadaSets.push_back(tempDP); //將對象壓入數(shù)據(jù)集合容器 ifs.close(); //關(guān)閉文件流 dataNum =i; //設(shè)置數(shù)據(jù)對象集合大小為i for(unsigned long i=0; i<dataNum;i++) SetArrivalPoints(dadaSets[i]); //計算數(shù)據(jù)點領(lǐng)域內(nèi)對象 函數(shù):將已經(jīng)過聚類算法處理的數(shù)據(jù)集合寫回文件 說明:將已經(jīng)過聚類結(jié)果寫回文件 char* fileName; //要寫入的文件名 bool ClusterAnalysis::WriteToFile(char* fileName ) ofstream of1(fileName); //初始化文件輸出流 for(unsigned long i=0; i<dataNum;i++) //對處理過的每個數(shù)據(jù)點寫入文件 for(int d=0; d<DIME_NUM ; d++) //將維度信息寫入文件 of1<<dadaSets[i].GetDimension()[d]<<'\t'; of1 << dadaSets[i].GetClusterId() <<endl; //將所屬簇ID寫入文件 of1.close(); //關(guān)閉輸出文件流 函數(shù):設(shè)置數(shù)據(jù)點的領(lǐng)域點列表 說明:設(shè)置數(shù)據(jù)點的領(lǐng)域點列表 void ClusterAnalysis::SetArrivalPoints(DataPoint& dp) for(unsigned long i=0; i<dataNum; i++) //對每個數(shù)據(jù)點執(zhí)行 double distance =GetDistance(dadaSets[i], dp); //獲取與特定點之間的距離 if(distance <= radius && i!=dp.GetDpId()) //若距離小于半徑,,并且特定點的id與dp的id不同執(zhí)行 dp.GetArrivalPoints().push_back(i); //將特定點id壓力dp的領(lǐng)域列表中 if(dp.GetArrivalPoints().size() >= minPTs) //若dp領(lǐng)域內(nèi)數(shù)據(jù)點數(shù)據(jù)量> minPTs執(zhí)行 dp.SetKey(true); //將dp核心對象標志位設(shè)為true dp.SetKey(false); //若非核心對象,,則將dp核心對象標志位設(shè)為false unsigned long ClusterAnalysis::DoDBSCANRecursive() unsigned long clusterId=0; //聚類id計數(shù),初始化為0 for(unsigned long i=0; i<dataNum;i++) //對每一個數(shù)據(jù)點執(zhí)行 DataPoint& dp=dadaSets[i]; //取到第i個數(shù)據(jù)點對象 if(!dp.isVisited() && dp.IsKey()) //若對象沒被訪問過,,并且是核心對象執(zhí)行 dp.SetClusterId(clusterId); //設(shè)置該對象所屬簇ID為clusterId dp.SetVisited(true); //設(shè)置該對象已被訪問過 KeyPointCluster(i,clusterId); //對該對象領(lǐng)域內(nèi)點進行聚類 clusterId++; //clusterId自增1 //cout << '孤立點\T' << i << endl; // cout <<'共聚類' <<clusterId<<'個'<< endl; //算法完成后,,輸出聚類個數(shù) 函數(shù):對數(shù)據(jù)點領(lǐng)域內(nèi)的點執(zhí)行聚類操作 說明:采用遞歸的方法,深度優(yōu)先聚類數(shù)據(jù) unsigned long dpID; //數(shù)據(jù)點id unsigned long clusterId; //數(shù)據(jù)點所屬簇id void ClusterAnalysis::KeyPointCluster(unsigned long dpID, unsigned long clusterId ) DataPoint& srcDp = dadaSets[dpID]; //獲取數(shù)據(jù)點對象 if(!srcDp.IsKey()) return; vector<unsigned long>& arrvalPoints = srcDp.GetArrivalPoints(); //獲取對象領(lǐng)域內(nèi)點ID列表 for(unsigned long i=0; i<arrvalPoints.size(); i++) DataPoint& desDp = dadaSets[arrvalPoints[i]]; //獲取領(lǐng)域內(nèi)點數(shù)據(jù)點 if(!desDp.isVisited()) //若該對象沒有被訪問過執(zhí)行 //cout << '數(shù)據(jù)點\t'<< desDp.GetDpId()<<'聚類ID為\t' <<clusterId << endl; desDp.SetClusterId(clusterId); //設(shè)置該對象所屬簇的ID為clusterId,,即將該對象吸入簇中 desDp.SetVisited(true); //設(shè)置該對象已被訪問 if(desDp.IsKey()) //若該對象是核心對象 KeyPointCluster(desDp.GetDpId(),clusterId); //遞歸地對該領(lǐng)域點數(shù)據(jù)的領(lǐng)域內(nèi)的點執(zhí)行聚類操作,,采用深度優(yōu)先方法 函數(shù):獲取兩數(shù)據(jù)點之間距離 說明:獲取兩數(shù)據(jù)點之間的歐式距離 DataPoint& dp1; //數(shù)據(jù)點1 DataPoint& dp2; //數(shù)據(jù)點2 返回值: double; //兩點之間的距離 */ double ClusterAnalysis::GetDistance(DataPoint& dp1, DataPoint& dp2) double distance =0; //初始化距離為0 for(int i=0; i<DIME_NUM;i++) //對數(shù)據(jù)每一維數(shù)據(jù)執(zhí)行 distance += pow(dp1.GetDimension()[i] - dp2.GetDimension()[i],2); //距離+每一維差的平方 return pow(distance,0.5); //開方并返回距離
5、算法調(diào)用
input.txt文件內(nèi)容 根據(jù)myClusterAnalysis.Init方法自行構(gòu)建,。
#include 'ClusterAnalysis.h' ClusterAnalysis myClusterAnalysis; //聚類算法對象聲明 myClusterAnalysis.Init('input.txt',100,5); //算法初始化操作,,指定半徑為100,,領(lǐng)域內(nèi)最小數(shù)據(jù)點個數(shù)為5 myClusterAnalysis.DoDBSCANRecursive(); //執(zhí)行聚類算法 myClusterAnalysis.WriteToFile('out.txt');//寫執(zhí)行后的結(jié)果寫入文件 system('pause'); //顯示結(jié)果
|