实习笔记Day9(2022.8.17)

一.总结

1.今天小组进行了初步分工,我和另一个同学负责 k-means 聚类及其并行优化这一部分 

2.在网上找了一份 k-means 聚类算法实现的c代码进行学习,以加深对其的理解 

二.学习笔记 

1.头文件及类定义 

#include<iostream>
#include<vector>
#include<map>
#include<cstdlib>
#include<algorithm>
#include<fstream>
#include<stdio.h>
#include<string.h>
#include<string>
#include<time.h>    //for srand
#include<limits.h>  //for INT_MIN INT_MAX
 
using namespace std;
 
template<typename T>   //类定义
class KMEANS
{
private:
	vector< vector<T> > dataSet; //数据集,每一个数据点是一个有x和y坐标的二维点
	vector< T > mmin,mmax;
	int colLen,rowLen;           //colLen:数据点维度;rowLen:数据点个数
	int k;                       //聚成k个簇
	vector< vector<T> > centroids; //k个簇的质心集合
	typedef struct MinMax        //存有最大最小值的结构体
	{
		T Min;
		T Max;
		MinMax(T min , T max):Min(min),Max(max) {}
	}tMinMax;
	typedef struct Node   //标识了每个数据点所属的簇类别,以及到质心的距离值
	{
		int minIndex; //the index of each node
		double minDist;
		Node(int idx,double dist):minIndex(idx),minDist(dist) {}
	}tNode;
	vector<tNode>  clusterAssment;  //存储了所有数据点的所属簇和距离信息的数组
 
	/*split line into numbers*/
	void split(char *buffer , vector<T> &vec); //将一行切分成多个数值放入容器
	tMinMax getMinMax(int idx);  //获取最大最小值
	void setCentroids(tMinMax &tminmax , int idx); //设置各个簇的质心
	void initClusterAssment();   //初始化每个数据点的所属簇和距离信息
	double distEclud(vector<T> &v1 , vector<T> &v2); //计算两个数据点的欧氏距离
 
public:
	KMEANS(int k);
	void loadDataSet(char *filename); //读入文件信息,初始化dataSet,colLen,rowLen
	void randCent();	//随机生成k个初始聚类中心
	void print();       //打印结果
	void kmeans();      //核心函数,计算k个质心以及每个数据点的分类
};

2.函数实现 

(1)构造函数初始化k  

template<typename T>
KMEANS<T>::KMEANS(int k)
{
	this->k = k;	
}

(2)获取所有数据点的idx分量的最大值和最小值 

//作用是获取所有数据点的idx分量的最大值和最小值
//数据点的idx分量是指数据点的下标为idx的那个值(每个数据点是一个向量vector)
template<typename T>
//返回值是类中定义的tMinMax结构体
typename KMEANS<T>::tMinMax KMEANS<T>::getMinMax(int idx)
{
    T min , max ;
	dataSet[0].at(idx) > dataSet[1].at(idx) ? ( max = dataSet[0].at(idx),min = 
    dataSet[1].at(idx) ) : ( max = dataSet[1].at(idx),min = dataSet[0].at(idx) ) ;
 
	for(int i=2;i<rowLen;i++)
	{
		if( dataSet[i].at(idx) < min )	min = dataSet[i].at(idx);
		else if( dataSet[i].at(idx) > max ) max = dataSet[i].at(idx);
		else continue;
	}
 
	tMinMax tminmax(min,max);
	return tminmax;
}

(3)设置k个质心的初始idx分量  

template<typename T>
void KMEANS<T>::setCentroids(tMinMax &tminmax,int idx)
{
	T rangeIdx = tminmax.Max - tminmax.Min;
	for(int i=0;i<k;i++)
	{
		/* generate float data between 0 and 1 */
		centroids[i].at(idx) = tminmax.Min + 
        rangeIdx *  ( rand() / (double)RAND_MAX ) ;
	}
}

(4)随机生成k个初始聚类中心函数randCent 

调用到了函数(2)和(4) 

template<typename T>
void KMEANS<T>::randCent()
{
	//先将k个质心都初始化为元素为全0的colLen维向量
	vector<T> vec(colLen,0);
	for(int i=0;i<k;i++)
	{
		centroids.push_back(vec);	
	}
 
	//set values by column
	srand( time(NULL) ); //根据当前时间生成随机数
    /* 调用setCentroids函数初始化k个质心的所有colLen个分量 */
	for(int j=0;j<colLen;j++)
	{
	    tMinMax tminmax = getMinMax(j);	
		setCentroids(tminmax,j);
	}
}

(5) 数据点信息数组clusterAssment初始化

template<typename T>
void KMEANS<T>::initClusterAssment()
{
	tNode node(-1,-1);
	for(int i=0;i<rowLen;i++)
	{
		clusterAssment.push_back(node);
	}
}
//将所有数据点所属簇编号以及到簇的质心的距离都初始化为-1

(6)计算两个数据点的欧氏距离

template<typename T>
double KMEANS<T>::distEclud(vector<T> &v1 , vector<T> &v2)
{
	T sum = 0;
	int size = v1.size();
	for(int i=0;i<size;i++)
	{
		sum += (v1[i] - v2[i])*(v1[i] - v2[i]);
	}
	return sum;
}

(7)打印函数print 

template<typename T>
void KMEANS<T>::print()
{
	ofstream fout;
	fout.open("res.txt");
	if(!fout)
	{
		cout<<"file res.txt open failed"<<endl;
		exit(0);
	}
 
	typename vector< vector<T> > :: iterator it = dataSet.begin();
	typename vector< tNode > :: iterator itt = clusterAssment.begin();
	for(int i=0;i<rowLen;i++)
	{
		typename vector<T> :: iterator it2 = (*it).begin();
		while( it2!=(*it).end() )
		{
			fout<<*it2<<"\t";
			it2++;
		}
		fout<<(*itt).minIndex<<endl;
		itt++;
		it++;
	}
 
}

(8)核心函数kmeans 

调用到了函数(5)(6)(7)

template<typename T>
void KMEANS<T>::kmeans()
{
	initClusterAssment();       //初始化clusterAssment数组
	bool clusterChanged = true; //用于检查迭代是否继续的标志
	//终止迭代的另一种方式可以是限制迭代次数
	while( clusterChanged ) 	
	{
		clusterChanged = false;
		//第一步:遍历每一个数据点,分别找到距离它们最近的簇
		cout<<"find the nearest centroid of each point : "<<endl;
		for(int i=0;i<rowLen;i++)
		{
			int minIndex = -1;
			double minDist = INT_MAX; //??
			//先计算数据点dataSet[i]到当前所有簇的质心的距离 
			for(int j=0;j<k;j++)
			{
				double distJI = distEclud( centroids[j],dataSet[i] );
				if( distJI < minDist )  //遍历当前所有质心
				{
					minDist = distJI;   //将minDist置为所有距离值最小者
					minIndex = j;       //将minIndex置为对应质心的编号
				}
			}
			//更新dataSet[i]的信息
			if( clusterAssment[i].minIndex != minIndex ) 
			{
				clusterChanged = true;//只要有一个数据点的分类情况还在变,就需要继续迭代
				clusterAssment[i].minIndex = minIndex;
				clusterAssment[i].minDist = minDist ;
			}
		}
 
		//第二步:更新k个簇的质心
		cout<<"update the centroids:"<<endl;
		for(int cent=0;cent<k;cent++) //遍历k个质心,一轮for完成更新一个质心
		{
			vector<T> vec(colLen,0); //vec初始化为colLen个元素0的向量
			int cnt = 0;
			for(int i=0;i<rowLen;i++) //对于每个质心,遍历rowLen个数据点
			{
                /* 如果找到数据点在当前质心所表示的簇内 */
				if( clusterAssment[i].minIndex == cent )	 
				{
					++cnt;
					for(int j=0;j<colLen;j++)	
					{
						vec[j] += dataSet[i].at(j);	
					}
				}
			}
            /* 对一个质心处理结束后,vec中存储的是在该质心代表的簇内
               所有数据点的总和,一一对应,cnt记录了该簇内的数据点个数 */ 
 
			//更新当前质心
			for(int i=0;i<colLen;i++)		
			{
				if( cnt!=0 )	vec[i] /= cnt;	
				centroids[cent].at(i) = vec[i];
			}
		}//完成一个质心的更新
		print();
	}

(9)将一行数据切分成多个数值放入容器

template<typename T>
void KMEANS<T>::split(char *buffer , vector<T> &vec)
{
	char *p = strtok(buffer," \t");
	while(p!=NULL)
	{
		vec.push_back( atof(p) ); //atof将字符串转换为double
		p = strtok( NULL," " ); 
	}
}

(10)加载数据集函数 

调用到了函数(9) 

template<typename T>
void KMEANS<T>:: loadDataSet(char *filename)
{
	FILE *pFile;
	pFile = fopen(filename,"r");
	if( !pFile )
	{
		printf("open file %s failed...\n",filename);
		exit(0);
	}
	
	//init dataSet
	char *buffer = new char[100];
	vector<T> temp;
	while( fgets(buffer,100,pFile) ) //每一次循环处理一行
	{
		temp.clear();
		split(buffer,temp);
		dataSet.push_back(temp);
	}
 
	//init colLen,rowLen 
	colLen = dataSet[0].size();
	rowLen = dataSet.size();
}

(11)main函数

int main( int argc , char *argv[])
{
	if(argc!=3)
	{
		cout<<"Usage : ./a.out filename k"<<endl;
		exit(0);
	}
 
	char *filename = argv[1];
	int k = atoi(argv[2]);
	KMEANS<double> kms(k);
	kms.loadDataSet(filename);
	kms.randCent();
	kms.kmeans();
 
	return 0;
}

三.工作记录 

暂无

注:代码来源http://t.csdn.cn/yTJ5Y 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Burp Suite 2022.6.1是Burp Suite的一个版本,它是一个用于Web应用程序渗透测试的工具。根据引用,您可以通过关注VX公众号401SecNote并回复"burp"来获取Burp Suite Professional v2022.6.1及其运行环境。此外,根据引用,您还可以通过百度网盘链接https://sysin.org/blog/burp-suite-pro-2022-6/下载Burp Suite Professional / Community 2022.6版本。如果您正在考虑安装高版本的Burp Suite,但担心与其他软件的兼容性问题,根据引用,您可以使用高版本的jdk来解决兼容性问题,并记录解决过程以备将来参考。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Burp Suite Professional 2022.6 (macOS, Linux, Windows) - Web 应用安全、测试和扫描](https://blog.csdn.net/netgc/article/details/125592616)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [笔记 | 在JAVA1.8环境下安装高版本Burp Suite Pro](https://blog.csdn.net/dust_hk/article/details/126489797)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值