层次聚类和固定宽度聚类

以下是头文件:

 
#ifndef WSNHSCDA_H
#define WSNHSCDA_H

#include "common.h"

//凡需要计算两个向量欧氏距离的类,都包含此类
class eucideanDistanceClass
{ 
public:
	static double eucideanDistance( const vector& f1, const vector& f2 ); //计算向量之间的欧氏距离
};


// 测量得到的数据向量,标示一个测量值。
// 每隔一段时间,传感节点进行测量,一个测量值有很多特征值。
// 此类保存一次取样得到的数据。
class dataSample{
public:
	dataSample():type(0)
	{
	
	};
	void operator()( dataSample & a)
	{
		cout<<"type = "<type = other.type;
		this->features = other.features;
		return *this;
	}
	unsigned int size()
	{
		return features.size();
	};
	double push_back( double val )
	{
		features.push_back(val);
	};
	double & operator[](unsigned int i)
	{
		return features[i];
	};
public:
	unsigned int type;
	vector features;
};

// 簇的总结:簇中所有向量的线性和,数据向量的个数,簇ID。
// 由于簇要进行融合和传递,融合后还是一个簇总结,所以还需要保存节点ID和融合之前的簇的ID。
// 此类方便于簇总结传递的管理。
class clusterSample  
{
public:
	clusterSample():featuresNum(0),clusterID(0),sensorID(0),isMerged(0)
	{
		return;
	};
	void featuresUpdate(const clusterSample &cS ,unsigned int num = 1 );//用于融合
	void featuresUpdate(const dataSample &dS ,unsigned int num = 1 );//用于聚类
	void operator()(clusterSample & cS)
	{
		cout<<"ID: "<(cS.featuresAvg);
	};
public:
	bool isMerged;
	vector featuresAvg;
	vector featuresSum;
	unsigned int featuresNum;
	unsigned int clusterID;//用于标示新的簇,簇ID
	unsigned int sensorID;//用于标示新的簇,产生这个簇的节点ID
	vector mergeClusters;//仅仅用于簇的融合。保存融合之前簇的信息。
private:
	void featuresAvgUpdate(unsigned int size); 
private:
	class eucideanDist :public eucideanDistanceClass
	{
	
	};
};

// 每个时间窗口的得到n个测量值。
// 在每一个节点上需要对测量值进行固定宽度聚类。
// 操作一个节点上的簇集合。包含原始的数据和簇信息。
// 此类方便节点自己管理自己的簇集合和子节点发送来的簇总结。
// 封装了关于节点对簇操作的所有逻辑,即是以节点为单位的。
class dataCluster  
{
public:
	dataCluster(vector & a, unsigned int sensorID = 0):dataSet(a),nodeID(sensorID)
	{
		return;
	}; 
	void fixedWidthCluster(double width);//对自身数据进行聚类
	unsigned int size()
	{
		return dataSet.size();
	};
public:
	static unsigned int clusterCount; //记录簇的个数
	vector dataSet;//节点自身的数据
	vector clusters;//节点根据自身的数据,构造出的簇集合
private:
	void normalize();
	class eucideanDist :public eucideanDistanceClass
	{
	
	};
	unsigned int nodeID;
protected:
	dataCluster()
	{
	
	};//为sensorNode单独构造的缺省构造函数
	friend class sensorNode;
};

//由于KNN算法结构比较复杂
//需要在这里对KNN算法内容进行封装
//仅仅需要在这个类里面封装的是KNN算法的逻辑部分
//KNN算法步奏描绘如下:
//1、每一个clusterSample包含了一个特征值的向量。
//2、对于簇集合中的每一个簇,计算其他所有簇和这个簇的距离。
//3、根据前K个距离,计算平均簇间距离。
//4、并返回由前K个值算出的均值组成的向量。
class KNNClass  
{
public:
	KNNClass(vector clusters,unsigned int k):clusters(clusters),k(k),AVGICD(0.0),SDICD(0.0)
	{
		dstMtrx.reserve(clusters.size());
	};
	double getAVGICD( )
	{
		return AVGICD; 
	};
	double getSDICD()
	{
		return SDICD; 
	};	
	void creatDistanceMatrix( );
	vector getICD()
	{  
		return ICD;
	};
private:
	void cnstrctICD();
	void calAVGICD();
	void calSDICD();
private:
	class eucideanDist:public eucideanDistanceClass
	{
	
	};
	const unsigned int k;
	vector clusters;
	vector > dstMtrx;
	vector ICD;
	double AVGICD;
	double SDICD;
};

// 在基站上进行KNN异常检测。
// 基站自己并不搜集数据,所以将dataCluster dC一项作为。
class BSNode 
{
public:
	BSNode(unsigned int nodeID = 0):nodeID(nodeID)
	{ 
	
	};
public:
	/*保存来自各个子节点的簇集的集合。以便于操作来自多个节点的簇集合。此时二维的。
	*第一维是各个节点。第二维是簇集合。
	*/
	vector clustersSet;
	vector dataSet;//将二维的来自不同节点的数据融合变为为一维的节点自身的数据
	const unsigned int nodeID;
private:		
	void anormalyDetectKNN(double anorm,unsigned int k);
private:	
	class eucideanDist:public eucideanDistanceClass
	{
	
	};
	//保存被检测出异常的簇
	vector clustersAnormal;
};

// 基站和节点是is a的关系。
// 每一个节点都是一个微型的基站。
// 1、搜集数据
// 2、对数据进行聚类
// 3、将聚类结果送到一跳父亲节点
// 4、需要对来自子节点的簇进行融合
// 5、需要进行异常检测
class sensorNode :private BSNode
{
public:
	sensorNode(dataCluster &a,unsigned int nodeID):BSNode(nodeID)
	{ 
		dC = a; 
	};
	void clusterMerge(double);
	void anormalyDetect(double anorm);
private:
	//继承来自于基站类的数据成员
	//保存来自各个子节点的簇集的集合。以便于操作来自多个节点的簇集合。
	//vector clustersSet;
	//自己节点上的数据
	dataCluster dC;
	class eucideanDist:public eucideanDistanceClass
	{
	
	};
};


void WSNHSCDATESTCPP();

#endif



以下是cpp文件:

#include "wsnHsCDA.h"


unsigned int dataCluster::clusterCount = 0; 

//计算特征量之间的欧氏距离
double eucideanDistanceClass::eucideanDistance( const vector& f1, const vector& f2 )
{
	vectorPrint(f1);
	vectorPrint(f2);
	assert( f1.size() == f2.size() );	
	double dist = 0.0;
	for( vector::size_type i = 0; i < f1.size(); i++ )
	{
		dist += pow(f1[i]-f2[i],2); 
	}
	return sqrt(dist);
}

//固定宽度聚类,发生在每一个节点上,对本地数据聚类。
//固定宽度聚类创建一个固定半径(宽度)的超球面簇集合。
//首先,随机选择任何数据点作为第一个以w为半径的簇的中心。
//通常,以欧式距离计算当前这个簇的中心和下一个待聚类数据向量的距离。
//如果这个距离小于W,这个数据向量就属于这个簇,然后更新中心点。
//如果距离大于w,就以这个数据向量为新的中心,构造一个新的簇。
void dataCluster::fixedWidthCluster(double width)
{
	bool found = false;
	clusterSample cs;
	cs.featuresUpdate(dataSet[0]);
	cs.clusterID = clusterCount;//对于新建立的簇要分配其簇ID
	cs.sensorID = nodeID;//对于新建立的簇要分配其节点ID
	dataSet[0].type = cs.clusterID;
	clusters.push_back(cs); 
	for( vector::size_type countD = 1; countD < dataSet.size(); countD++ ) // 遍历数据集
	{	
		found = false;
		 for(vector::size_type countC = 0; countC < clusters.size(); countC++ )//遍历簇集
		 {  
			 if( eucideanDist::eucideanDistance( dataSet[countD].features,clusters[countC].featuresAvg ) < width )//加入类别
			 { 
				cout<<"*****dis is: "<::size_type countCSet1 = 0; countCSet1 < clustersSet.size(); countCSet1++ )//从第一个节点开始上的簇集开始
	{
		dataCluster dC1 = clustersSet[countCSet1];//取出第一个节点上的簇集
		for( vector::size_type countCSm1 = 0; countCSm1 < dC1.clusters.size(); countCSm1++ )//从第一个簇开始
		{
			clusterSample cS1 = dC1.clusters[countCSm1];//取出第一个簇集上的簇
			if( true == cS1.isMerged )//此簇已经融合,进入到下一个簇
			{
				continue;
			}
			for( vector::size_type countCSet2 = countCSet1 +1; countCSet2 < clustersSet.size(); countCSet2++)//从下一个节点开始
			{
				dataCluster dC2 = clustersSet[countCSet2];//取出簇集合
				for(vector::size_type countCSm2 = 0; countCSm2 < dC1.clusters.size(); countCSm2++)
				{
					clusterSample cS2 = dC1.clusters[countCSm2]; //取出簇
					if( true == cS2.isMerged )
					{
						continue;
					}
					if( eucideanDist::eucideanDistance(cS1.featuresAvg,cS2.featuresAvg) < w )
					{
						clusterSample cs;
						cs.featuresUpdate(cS1,cS1.featuresNum);//将两个簇sample合并为一个簇
						cs.featuresUpdate(cS2,cS2.featuresNum);
						dC.clusters.push_back(cs);//并将此簇加入到当前节点的簇集合中
						cS1.isMerged = true;
						cS2.isMerged = true;
					}
				}
			}
		}
	}
	//然后,融合到自己的簇集合	
	//最后在遍历子节点发来的簇集的过程中,
	//对没有融合的所有簇,都添加进节点自身的簇集合dC
	for( vector::size_type countCS3 = 0; countCS3 < dC.clusters.size(); countCS3++ )//从第一个簇开始(dataCluster dC)
	{
		if( true == dC.clusters[countCS3].isMerged )
		{
			continue;
		}
		for( vector::size_type countCSet3 = 0; countCSet3 < clustersSet.size(); countCSet3++)//从第一个节点开始
		{
				dataCluster dC3 = clustersSet[countCSet3];//取出簇集合
				for(vector::size_type countCSm3 = 0; countCSm3 < dC3.clusters.size(); countCSm3++)
				{
					if( true == dC3.clusters[countCSm3].isMerged )//已经融合过的不再融合
					{
						continue;
					}
					if( eucideanDist::eucideanDistance(dC.clusters[countCS3].featuresAvg,dC3.clusters[countCSm3].featuresAvg) < w )
					{
						clusterSample cs;
						cs.featuresUpdate(dC.clusters[countCS3],dC.clusters[countCS3].featuresNum);//将两个簇sample合并为一个簇
						cs.featuresUpdate(dC3.clusters[countCSm3],dC3.clusters[countCSm3].featuresNum);
						dC.clusters.push_back(cs);//并将此簇加入到当前节点的簇集合中
						dC.clusters[countCS3].isMerged = true;
						dC3.clusters[countCSm3].isMerged = true;
					}
					else
					{
						dC.clusters.push_back(dC3.clusters[countCSm3]);//并将此簇加入到当前节点的簇集合中,并不在融合
						//那么融合后,此节点的簇集合就是dC中没有被标记isMerged的所有簇
					}

				}
		}
	}
	return;
}

//对节点自身的数据进行归一化处理
void dataCluster::normalize()
{
	assert( dataSet.size() ); //确保数据集不为空
	vector dataSet;
	vector avg;
	avg.reserve(dataSet[0].size());
	vector stdDiv;
	stdDiv.reserve(dataSet[0].size());
	for( unsigned int count1 = 0; count1 < dataSet.size(); count1++ )//求出各个特征值在各个特征向量的和。
	{
		for( unsigned int count2 = 0; count2 < dataSet[count1].size(); count2++ )
		{
			avg[count2] += dataSet[count1][count2];
		}
	}
	for( unsigned int count3 = 0; count3 < avg.size(); count3++ )//求出均值。
	{
		avg[count3] /= dataSet.size();
	}
	for( unsigned int count4 = 0; count4 < dataSet.size(); count4++ )
	{
		for( unsigned int count5 = 0; count5 < dataSet[count4].size(); count5++ )
		{
			stdDiv[count5] += pow(dataSet[count4][count5]-avg[count5],2);
		}
	}//求出标准方差。
	for( unsigned int count6 = 0; count6 < stdDiv.size(); count6++ )//求出均值。
	{
		stdDiv[count6] = sqrt(stdDiv[count6]);
	}
	//归一化。
	for( unsigned int count1 = 0; count1 < dataSet.size(); count1++ )//求出各个特征值在各个特征向量的和。
	{
		for( unsigned int count2 = 0; count2 < dataSet[count1].size(); count2++ )
		{
			dataSet[count1][count2] = (dataSet[count1][count2] - avg[count2])/stdDiv[count2];
		}
	}
}

void clusterSample::featuresAvgUpdate(unsigned int size )
{
	if( featuresAvg.size() != 0 )
	{
		 for( vector::size_type i = 0; i < featuresSum.size();i++ )
			 featuresAvg[i] = featuresSum[i]/featuresNum;
	}
	else{
		for( vector::size_type i = 0; i < size; i++ )
			 featuresAvg.push_back(featuresSum[i]/featuresNum);
	}
	return;
}

void clusterSample::featuresUpdate(const clusterSample &cS,unsigned int num  )
{
	featuresNum += num;
	if( featuresSum.size() != 0 )
	{
		 for( vector::size_type i = 0 ; i <  featuresSum.size(); i++ )
			 featuresSum[i] = featuresSum[i]+cS.featuresAvg[i];
	}
	else{
		for( vector::size_type i = 0; i < cS.featuresAvg.size(); i++ )
			 featuresSum.push_back(cS.featuresAvg[i]);
	}
	mergeClusters.push_back(cS);
	featuresAvgUpdate(cS.featuresAvg.size());
	return;
}
void clusterSample::featuresUpdate(const dataSample &dS ,unsigned int num  )
{
	featuresNum += num;
	if( featuresSum.size() != 0 )
	{
		 for( vector::size_type i = 0 ; i <  featuresSum.size(); i++ )
			 featuresSum[i] = featuresSum[i]+dS.features[i];		 
	}
	else{
		for( vector::size_type i = 0; i < dS.features.size(); i++ )
			 featuresSum.push_back(dS.features[i]);
	}
	featuresAvgUpdate(dS.features.size());
	return;
}

void KNNClass::calAVGICD()
{
	unsigned int count = 0;
	for( vector::size_type countdM1 = 0; countdM1 < dstMtrx.size(); countdM1++ )
	{
		for( vector::size_type countdM2 = 0; countdM2 <= dstMtrx[countdM1].size(); countdM2++ )
		{
			AVGICD += dstMtrx[countdM1][countdM2];
			count++;
		}
	}
	AVGICD /= (2*count); 
}
void KNNClass::calSDICD()
{
	unsigned int count = 0;
	for( vector::size_type countdM1 = 0; countdM1 < dstMtrx.size(); countdM1++ )
	{
		for( vector::size_type countdM2 = 0; countdM2 <= dstMtrx[countdM1].size(); countdM2++ )
		{
			SDICD += pow(dstMtrx[countdM1][countdM2] - AVGICD,2);
			count++;
		}
	}
	SDICD = sqrt( SDICD/(count-1) );
}

void KNNClass::cnstrctICD( )
{
	unsigned temp = ( k > dstMtrx.size() ) ? dstMtrx.size()-1 : k ;

	for( vector::size_type countdM1 = 0; countdM1 < dstMtrx.size(); countdM1++ )
	{
		for( vector::size_type countdM2 = 0; countdM2 <= temp; countdM2++ )
		{
			ICD[countdM1] += dstMtrx[countdM1][countdM2];
		}
		ICD[countdM1] /= k;
	}
}

void KNNClass::creatDistanceMatrix( )
{
	for( vector::size_type countcS1 = 0; countcS1 < clusters.size(); countcS1++ )
	{
		for( vector::size_type countcS2 = countcS1 + 1; countcS2 < clusters.size(); countcS2++ )
		{
			dstMtrx[countcS1][countcS2] = dstMtrx[countcS2][countcS1] = 
				eucideanDist::eucideanDistance(clusters[countcS1].featuresAvg,clusters[countcS2].featuresAvg);
		}
		dstMtrx[countcS1][countcS1] = 0.0;
		sort(dstMtrx[countcS1].begin(),dstMtrx[countcS1].end());
	}
	cnstrctICD( );
	calAVGICD();
	calSDICD();
}

//在节点上执行,此处实现在节点上运行的,
void sensorNode::anormalyDetect(double anorm)
{

	return;
}

//在基站上执行。
//基站上汇聚有全网络搜集的数据
//以KNN为基础,实现全局异常簇的识别。
//并以簇为检测单位的一次检测算法。
//论文中并没有讲明白这个平均簇间距离如何求。
//也没有说清楚标准方差如何求。
void BSNode::anormalyDetectKNN(double anorm,unsigned int k)
{	
	KNNClass knnobject(dataSet,k);
	knnobject.creatDistanceMatrix( );
	//求出所有簇间距离的均值。
	//求出所有簇间距离的方差。
	//筛选出异常簇。
	for( vector::size_type countdM1 = 0; countdM1 < knnobject.getICD().size(); countdM1++ )
	{
		 if(  knnobject.getICD()[countdM1] > knnobject.getAVGICD() + anorm*knnobject.getSDICD() )
			 clustersAnormal.push_back(dataSet[countdM1]);
	}
	return;
}

// 以下实验数据,共计三个簇。
// 分别为:1,2,3,4;   5,6,7,8;    9,10,11,12.
// 当width取值为40-100之间时,可以分为三个簇。
void WSNHSCDATESTCPP()
{
	
	vector dataSet;
	dataSample d1;
	d1.features.push_back(1.0); //x
	d1.features.push_back(2.0); //y
	dataSample d2;
	d2.features.push_back(1.1); //x
	d2.features.push_back(2.1); //y
	dataSample d3;
	d3.features.push_back(0.5); //x
	d3.features.push_back(2.0); //y
	dataSample d4;
	d4.features.push_back(1.5); //x
	d4.features.push_back(2.9); //y
	dataSet.push_back(d1);
	dataSet.push_back(d2);
	dataSet.push_back(d3);
	dataSet.push_back(d4);
	dataSample d5;
	d5.features.push_back(1.0); //x
	d5.features.push_back(112.0); //y
	dataSample d6;
	d6.features.push_back(10.1); //x
	d6.features.push_back(102.1); //y
	dataSample d7;
	d7.features.push_back(0.5); //x
	d7.features.push_back(132.0); //y
	dataSample d8;
	d8.features.push_back(5.5); //x
	d8.features.push_back(120.9); //y
	dataSet.push_back(d5);
	dataSet.push_back(d6);
	dataSet.push_back(d7);
	dataSet.push_back(d8);
	dataSample d9;
	d9.features.push_back(111.0); //x
	d9.features.push_back(2.0); //y
	dataSample d10;
	d10.features.push_back(121.1); //x
	d10.features.push_back(32.1); //y
	dataSample d11;
	d11.features.push_back(100.5); //x
	d11.features.push_back(2.0); //y
	dataSample d12;
	d12.features.push_back(111.5); //x
	d12.features.push_back(2.9); //y
	dataSet.push_back(d9);
	dataSet.push_back(d10);
	dataSet.push_back(d11);
	dataSet.push_back(d12);
	cout<<"数据集大小为: "<


 
  

你可能感兴趣的:(机器学习与数据挖掘,C++基础技术,dataset,class,KMEANS,each,类)