Kmeans文本聚类系列之如何调用Preprocess类

注意:

本代码中没有实现“C++工程调用weka”的功能,如果您要找这类的资料,那么您来错地方了。重申一下这份代码的目的:方便广大自然语言处理爱好者,研究者,不必过分究竟于编程的技术细节,而是能在一开始就将注意力集中在文本分类/聚类这个主题上。

拿我自己做个比方吧,我一直怀疑课本上所讲的各种特征词选择方法是否有效,比如课本上说DF法与IG法,CHI squire法效果差不多,MI法效果最差。我还怀疑课本上所讲的:多重伯努利贝叶斯的分类效果要劣于多项式贝叶斯的分类效果。所以总想实验一下。可是,如果完成这样一项实验,需要花费很大力气,即便是我可以调用weka中的算法,那么繁杂的预处理过程也是十分耗时的。这也是我共享这份代码的初衷。

另外,比如我想结合自己的专业背景学习下Libsvm.可是发现libsvm网站上所给的数据都是UCI等国外大学提供的,和自己的专业也不太相关。

在咱们国内可供开源的学习资料太少了。就说进行文本分类的语料库吧,除了搜狗一家之外,没有免费提供的。一些人把这种很底层的资源,奉若神明,当成宝贝一样供起来。所以我们所看到的好的开源的软件库,算法库都是老外搞的,如lucene。

我想国人把“糟粕”当成宝贝珍藏起来,大概有两个原因:一个是:对自己太不自信了,生怕自己的东西被别人偷师学了去(这也证明 他的水平根本也不咋地,人家一学就会,太低端了),其实拿出来,让别人多指点下岂不是进步更快呢?第二个是:中国的剽窃现象太多了。

这里上两张图吧。

QQ截图未命名

QQ截图未命名2

“源码下载网”不仅剽窃了我在CSDN上上传的资源,而且还在其中加入了一些成人用品广告,如果在网页挂马,植入病毒就更加大逆不道了。。。。

好像有点跑题了。

接着说Preprocess类。

首先为该类的私有数据成员赋值,这些变量包括文件的储存地址,数据库的链接字符串等等。

private:
        char *bagofwordsAddress;//存放词袋子模型的位置
        char * featurewordsAddress;//存放特征词文件的位置;
        char *arffFileAddress;//存放ARFF文件的位置
        char *infoFromWekaAddress;//存放调用weka后的实验结果
        char *articleIdsAddress;//存放被聚类的文章的ID号
        char *dbconnection;//数据库的链接字符串
        char *dbselect;//数据库select语句
        char *dbfield;//数据库字段
        int beginIndex;//开始聚类的文章id
        int endIndex;//结束聚类的文章id

该类提供两个函数。第一个函数完成:建立词袋子模型,特征词选择,建立文档向量模型,并将文档向量模型格式化成arff文件格式。第二个函数完成:从weka聚类信息输出文件获取聚类中心,完成文本聚类,并且输出聚类结果。这两个函数代码见如下:

第一个函数:

void Preprocess::WriteTotalArff(char *dbfield,int DFthreshold,bool isbagOfWordsExist,FUNCSEG seg)

{

	

	

	map<string,vector<pair<int,int>>> mymap;

	if(!isbagOfWordsExist)

	{

		ConstructMap(mymap,dbfield,seg);

		save(mymap);

		cout<<"词袋子信息已经保存到硬盘"<<endl;

	}

	else

	{

		load(mymap);

	}

	DFcharicteristicWordSelection(mymap,DFthreshold);

	WriteHeadArff();

	VSMFormation(mymap);

	cout<<"arff文件已经形成"<<endl;

	

	

	string temp(infoFromWekaAddress);



	cout<<"请您将使用weka聚类,并保存为"<<temp<<endl;

}
 
第二个函数
void Preprocess::RetreiveArticleInfoFromDataBase()

{

	map<string,vector<pair<int,int>>> mymap;

	vector<pair<int,string>>resultInfo;

	map<string,vector<double> >clusters;

	map<int,vector<double> >vsmMatrix;

	map<string,vector<int>> articlesInfo;

	ofstream ofile("F:\\cluster\\ArticlesInPerCluster.txt");

	//boost::regex_replace(strresult)

	//ConstructMap(mymap,1,500);

	//save(mymap);

	load(mymap);

	vsmMatrix=VSMConstruction(mymap);

	clusters=GetClusters();

	resultInfo=GenerateClusterInfo(vsmMatrix,clusters);

	articlesInfo=FetchArticlesOFClusters(clusters,resultInfo);



	/*for(map<string,vector<int>>::iterator it=articlesInfo.begin();it!=articlesInfo.end();it++)

	{

		ofile<<it->first<<endl;

		int count=0;

		ofile<<"(";

		for(int i=0;i<it->second.size();i++)

		{

			ofile<<(it->second)[i];



			if(count<it->second.size()-1)

			{

				ofile<<",";

			}

			count++;

		}

		ofile<<")";

		ofile<<endl;





	}*/

	for(map<string,vector<int>>::iterator it=articlesInfo.begin();it!=articlesInfo.end();it++)

	{

		ostringstream out;

		string selectassist;

		char *selectsql=new char[5000];

		int count=0;

		CoInitialize(NULL);

		_ConnectionPtr pConn(__uuidof(Connection));

		_RecordsetPtr pRst(__uuidof(Recordset));

		pConn->ConnectionString=dbconnection;

		pConn->Open("","","",adConnectUnspecified);

		cout <<it->first<<endl;

		ofile<<it->first<<endl;

		out<<"(";

		count=0;

		for(int i=0;i<it->second.size();i++)

		{

			out<<(it->second)[i];

			if(count<it->second.size()-1)

			{

				out<<",";

			}

			count++;

			

		

		}

		out<<")";

		selectassist=out.str();

		sprintf_s(selectsql,5000,"%s %s","Select ArticleTitle,class from News Where ArticleId in ",selectassist.c_str());



		pRst=pConn->Execute(selectsql,NULL,adCmdText);

		while(!pRst->rsEOF)

		{	

		//string keywordstr=(_bstr_t)pRst->GetCollect("CKeyWord");

			string title=(_bstr_t)pRst->GetCollect("ArticleTitle");

			//string rawtext=(_bstr_t)pRst->GetCollect("ArticleText");

			string categorization=(_bstr_t)pRst->GetCollect("class");

			cout<<"文章标题:"<<title<<"文章所属类别: "<<categorization<<endl;

			ofile<<"文章标题:"<<title<<"文章所属类别: "<<categorization<<endl;





			

		





			pRst->MoveNext();

			

		}

		pRst->Close();

		pConn->Close();

		pRst.Release();

		pConn.Release();

		CoUninitialize();

	

	}

	

	





ofile.close();	

	

	

}

在main函数中各种字符串:

 Preprocess::FUNCSEG seg=&Preprocess::goodWordsinPieceArticle;

	int beginIndex=1;

	int endIndex=66;

	const char *bagofwordsAddress="F:\\cluster\\mydict.dat";//存放词袋子模型的位置

	const char * featurewordsAddress="F:\\cluster\\keywordsinfo.dat";//存放特征词文件的位置;

	const char *arffFileAddress="F:\\cluster\\tobeClustered.arff";//存放ARFF文件的位置

	const char *infoFromWekaAddress="F:\\cluster\\InfoFromWeka.dat";//存放调用weka后的实验结果

	const char * articleidAddress="F:\\cluster\\clusteredArticleId.dat";//存放已经已经被聚类的文章ID

	const char *conn="Provider=SQLOLEDB.1;Password=xxxx;Persist Security Info=True; User ID=sa;Initial Catalog=MyNews";

    char *firstpart="select ArticleId,ArticleTitle,ArticleText from News where ArticleId between";

	char *lastpart="order by ArticleId";

	char selectsql[1000]={'\0'};

	char *dbfield="ArticleText";

	sprintf_s(selectsql,1000,"%s %d and %d %s",firstpart,beginIndex,endIndex,lastpart);

	int string_size=600;



	Preprocess  p(string_size,bagofwordsAddress,featurewordsAddress,arffFileAddress,infoFromWekaAddress,articleidAddress,conn,selectsql,beginIndex,endIndex);
 
 
调用第一个函数:(注意:由于tobeClustered.arff文件为ios::app格式打开,所以每次开始新的实验之前要TruncateArff()清空下)
p.TruncateArff();

	

p.WriteTotalArff(dbfield,10,false,seg);

(注意:WrtieTotalArff函数中的false/true表示是否重新建立词袋子模型,如果是false 则表示不再建立词袋子模型了,比如我们想在原来的数据上重新做实验只想改一下DF阈值,从10改成20
这时候就没有必要再重新建立词袋子模型)
最后的运行结果:
QQ截图未命名2 
此系列已经写完,下一篇博文将上传源代码,和66篇三类新闻的语料资源。
末了加一句:虽然我的初衷是建立一个开源的预处理框架,但是由于个人水平有限,
可能整个程序框架会令读者有诸多不满。欢迎大家多提意见。同时也希望我这篇博文能起到
抛砖引玉的作用。
最后再次感谢园友嗷嗷 以及Galactica 在我编写C++程序中给予我的帮助,这是我第一个C++
项目程序,函数命名,变量命名有点乱,希望大家不要学,能够取其精华,去其糟粕。

你可能感兴趣的:(process)