• Kmeans 聚类之建立文档向量模型(VSM)


    作者:finallyliuyu 转载使用等请注明出处

    在上一篇博文《Kmeans聚类之特征词选择DF》中我们已经给出了特征词选择的代码,这里我们将给出建立文档向量模型的代码,以及将文档向量模型写成Weka数据格式的代码。关于Weka数据格式等相关内容,请见:教程

    首先我们给出写Arff头文件的代码

    void Preprocess::WriteHeadArff()
    {
    	ofstream ofile(arffFileAddress,ios::binary);
    	ofile<<"@relation aticle"<<endl;
    	ofile<<"\n";
    	vector<string> myKeys=GetFinalKeyWords();
    	for(vector<string>::iterator it=myKeys.begin();it!=myKeys.end();it++)
    	{
    		//string temp="@attribute "+"'"+(*it)+"'"+" real";
    		string temp="";
    		temp+="@attribute ";
    		temp+="'";
    		temp+=*(it);
    		temp+="'";
    		temp+=" real";
    		/*strcpy(temp,"@attribute ");
    		strcpy(temp,"'");
    		strcpy(temp,*(it));
    		strcpy(temp,"'");
    		strcpy(temp," real");*/
    
    		ofile<<temp<<endl;
    	}
    	ofile<<"\n"<<endl;
    	ofile<<"@data"<<endl;
    	ofile.close();
    }

    下面重点介绍采用TF-IDF权重建立文档向量模型:

    在给出代码之前先简要介绍下什么是TF,DF

    对于一个特定的Term t

    TF,指的是它在吗某一篇文章中出现的次数;

    DF,指的是整个文档集合中出现该词的文章篇数;

    文档向量模型(Vector Space Model):向量。向量的属性为用《Kmeans聚类之特征词选择DF》中的特征词选择方法选定的特征词。

    整个文档集合的VSM模型实际上是以矩阵的格式保存的。矩阵的每一行,代表一篇文章,是一个文档向量。

    TF-IDF模型有很多权重计算模式:(注意:以下截图来自于计算所王斌老师的课件《现代信息检索》)在这里顺便给大家介绍一本十分不错的书《信息检索导论》 (Introduction to Information Retrieval)原版第一作者为斯坦福大学计算机语言学副教授Christopher D. Manning。该书由王斌老师翻译成中文,现在已经出版。

    TF权重计算模式:

    QQ截图未命名

    IDF权重计算模式:

    QQ截图未命名2

    归一化方式:

    QQ截图未命名3

    考虑到一篇文章可能完全不含有我们用DF选择法选择的特征词。

    那么这篇文章的VSM就是{0,0,0,..0}

    为了避免产生这种类型的稀疏数据,我采用的TF-IDF计算模式为

    a-l-c。

    大家对应上面三个表找一下,就找到相应的计算公式了。

    下面开始建立文档向量模型:

    获得每个特征词对应的maxTF和DF:

    ector<pair<int,int> >Preprocess::GetfinalKeysMaxTFDF(map<string,vector<pair<int,int>>> &mymap)
    {
    	vector<pair<int,int> >maxTFandDF;
    	vector<string>myKeys=GetFinalKeyWords();
    	for(vector<string>::iterator it=myKeys.begin();it!=myKeys.end();it++)
    	{  
    		int DF=mymap[*it].size();
    		int maxTF=0;
    		for(vector<pair<int,int> >::iterator subit=mymap[*it].begin();subit!=mymap[*it].end();subit++)
    		{
    			if(subit->second>maxTF)
    			{
    				maxTF=subit->second;
    			}
    
    		}
    		maxTFandDF.push_back(make_pair(maxTF,DF));
    		//find_if(mymap[*it].begin(),mymap[*it].end(),
    	}
    	return maxTFandDF;
    }
    ************************************************************************/
    /* 文档向量模型归一化                                                                     */
    /************************************************************************/
    vector<pair<int,double> >Preprocess::NormalizationVSM(vector<pair<int,double> > tempVSM)
    {
    
    	double sum=0;
    	for(vector<pair<int,double> >::iterator vsmit=tempVSM.begin();vsmit!=tempVSM.end();++vsmit)
    	{
    		sum+=pow(vsmit->second,2);
    	}
    	for(vector<pair<int,double> >::iterator vsmit=tempVSM.begin();vsmit!=tempVSM.end();++vsmit)
    	{
    		vsmit->second/=sqrt(sum);
    	}
    	return tempVSM;
    
    }
    有了上面的辅助函数,那么我们可以一边对文档集合建立文档向量模型,一边写arff文件的data部分了。
    首先还要给出两个辅助函数,分别完成浮点数和整数字符串化的功能
    /************************************************************************/
    /* 将整数转化成字符串                                                   */
    /************************************************************************/
    
    string Preprocess::do_fraction(int val)
    {
    	ostringstream out;
    	out<<val;
    	string str= out.str(); //从流中取出字符串
    	str.swap(string(str.c_str()));//删除nul之后的多余字符
    	return str;
    
    }
     
     
    /************************************************************************/
    /* 将浮点数转化成指定精度的字符串                                       */
    /************************************************************************/
    string Preprocess::do_fraction(double val,int decplaces)
    {
    	
    	//int prec=numeric_limits<double>::digits10;
    	char DECIMAL_POINT='.'; 
    	ostringstream out;
    	//out.precision(prec);
    	out<<val;
    	string str=out.str();
    	size_t n=str.find(DECIMAL_POINT);
    	if((n!=string::npos)&&n+decplaces<str.size())
    	{
    		str[n+decplaces]='\0';
    	}
    	str.swap(string(str.c_str()));
    
    	return str;
    }

    将一篇文档的VSM字符串化的函数:

    ************************************************************************/
    /*              单个文档向量模型字符串化                                                        */
    /************************************************************************/
    string Preprocess::FormatVSMtoString(vector<pair<int,double> > tempVSM)
    {
    	string ret="{";
    	int commaindication=0;
    	for(vector<pair<int,double> >::iterator vsmit=tempVSM.begin();vsmit!=tempVSM.end();++vsmit)
    	{   
    
    		ret+=do_fraction(vsmit->first)+" "+do_fraction(vsmit->second,8);
    		if(commaindication<tempVSM.size()-1)
    		{
    			ret+=",";
    		}
    		commaindication++;
    	}
    	ret+="}";
    	return ret;
    }

    下面的函数调用上面的FormatVSMtoString 填写arff文件的data字段

    /************************************************************************/
    /* 将实验数据写成arff @data格式                                                                     */
    /************************************************************************/
    void Preprocess::VSMFormation(map<string,vector<pair<int,int>>> &mymap)
    {   int corpus_N=endIndex-beginIndex+1;
    	ofstream ofile1(articleIdsAddress,ios::binary);//保存文章编号的文件
    	ofstream ofile2(arffFileAddress,ios::binary|ios::app);
    
    	vector<string> myKeys=GetFinalKeyWords();
    	vector<pair<int,int> >maxTFandDF=GetfinalKeysMaxTFDF(mymap);
    	for(int i=beginIndex;i<=endIndex;i++)
    	{   vector<pair<int,double> >tempVSM;
    		for(vector<string>::size_type j=0;j<myKeys.size();j++)
    		{
    		//vector<pair<int,int> >::iterator findit=find_if(mymap[myKeys[j]].begin(),mymap[myKeys[j]].end(),PredTFclass(i));
    			double TF=(double)count_if(mymap[myKeys[j]].begin(),mymap[myKeys[j]].end(),PredTFclass(i));
    
    
    			TF=0.5+0.5*(double)TF/(maxTFandDF[j].first);
    			TF*=log((double)corpus_N/maxTFandDF[j].second);
    			if(TF!=0)
    			{
    				tempVSM.push_back(make_pair(j,TF));
    
    			}
    
    
    
    		}
    		if(!tempVSM.empty())
    		{
    			tempVSM=NormalizationVSM(tempVSM);
    			string vsmStr=FormatVSMtoString(tempVSM);
    			ofile1<<i<<endl;
    			ofile2<<vsmStr<<endl;
    		}
    		tempVSM.clear();
    
    
    
    	}
    	ofile1.close();
    	ofile2.close();
    
    
    }
    至此文档向量模型建立模块的代码已经介绍完毕。
    未完,待续,下次我们将介绍如何从weka获得计算出的聚类中心,完成文本聚类。
  • 相关阅读:
    EasyNVR摄像机网页无插件直播方案H5前端构建之:通道内部搜索功能的实现方案与代码
    EasyNVR摄像机网页无插件直播方案H5前端构建之:bootstrap弹窗功能的实现方案与代码
    EasyNVR摄像机网页无插件直播方案H5前端构建之:bootstrap-datepicker日历插件的实时动态展现
    EasyNVR摄像机网页无插件直播方案H5前端构建之:如何播放HLS(m3u8)直播流
    EasyNVR摄像机网页无插件直播方案H5前端构建之:区分页面是自跳转页面还是分享页面
    EasyNVR摄像机网页无插件直播方案H5前端构建之:如何区分PC端和移动端
    EasyDSS高性能流媒体服务器开发RTMP直播同步输出HLS(m3u8)录像功能实现时移回放的方案
    Stack Overflow: The Architecture
    The week in .NET
    十分钟轻松让你认识Entity Framework 7
  • 原文地址:https://www.cnblogs.com/finallyliuyu/p/1817322.html
Copyright © 2020-2023  润新知