VS2010简单实现-C++-宋词词频统计-实验报告-附源代码_第1页
VS2010简单实现-C++-宋词词频统计-实验报告-附源代码_第2页
VS2010简单实现-C++-宋词词频统计-实验报告-附源代码_第3页
VS2010简单实现-C++-宋词词频统计-实验报告-附源代码_第4页
VS2010简单实现-C++-宋词词频统计-实验报告-附源代码_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

实验一词频统计模型方法本词频统计代码的主要方法如下:本程序的开发环境是VS2010,使用的编程语言是C++。(2)不采用char*类型的字符串而采用C++标准程序库中的string类,是因为它和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,它集成的操作函数足以完成我们大多数情况下(甚至是100%)的需要。因此我采用字符串作为数据处理类型,在程序中主要用来存储每次从文件流中读取的一段字符串swhole,临时保存单个词语的sdanci,保存所有不重复单词的sdanciwh,保存抽取出的高频单词的spaixu。(3)使用string类的函数substr(nstart,nlength)来从字符串中截取指定长度字符串。(4)使用string类的函数find(s)来查找指定字符串。(5)使用长整型数组count[alength]存储每个单词对应的频度(6)词频统计思想:每次从语料中读取一段到swhole中,从头开始,首先判断将要取的四个字节(即两个中文字符)是否包含中文标点,若全是汉字则截取这四个字节存入sdanci,在sdanciwh中查找是否存在该单词,如果已存在,就将频度数组count[]相应位加1,如果不存在就将该词添加到sdanciwh,同时将总单词数ndanci+1。(7)本程序采用快速排序算法进行排序,关于针对单词和频度同时进行排序的技巧详见第三部分系统设计。(8)利用一个变量来实现系统功能的转换,如定义整型变量dancil来规定程序统计的是单字,双字,或是三字的词语。系统设计系统详细的设计流程主要分为两部分,一是读取文本文件并进行单词频度统计。二是对统计到的单词频度进行处理,筛选出高频词汇并输出到文本中。(一)单词频度统计的具体流程:系统初始化:定义各种变量类型,分为全局变量和局部变量,设定程序的文件输入输出流并初始化。全局变量主要用来设定可以控制程序功能和执行程度的变量。如alength可以控制程序扫描文档的终止位置,b[maxnum]是用来存储参与排序的临时数组变量。(2)每次从文件流中读入一段数据,若这段数据是一个宋词词牌名,则直接从文件流中读取下一段数据,因为词牌名并不参与词频统计。(3)针对这一段数据,开始统计词频。比如“犹解嫁东风”这句话,可能的二字组合是“犹解”“解嫁”“嫁东”“东风”,每次读取两个字,然后先在词库中查找是否已存在该词,若存在则将频度数组相应位加一,若不存在,则将该词加入到词库中,并将单词数量加一。注意:这里的词库采用一个字符串来存储所有读取到的不重复词语。(4)关于(3)中的标点处理。比如“高频词汇,数组”这个字符串,我们不能让程序将“汇,”与“,数”识别为一个词语。我的处理是当字符位置变量读取到“汇”字之前时就自动将该变量移到“数”前,为防止移动后再次遇到标点,还应做到自动跳过前方的一个标点。这些在处理代码中已十分清楚。关于单词频度统计的系统流程图(使用亿图制作)如下:筛选出高频词汇并排序(1)由于统计词频是按照文本文件从前到后统计的,所以频度数组的内容完全是无序的。若直接对该数组排序,将引起十分庞大的复杂度。这里通过对频度数组内的频度进行筛选,只选出高频词汇,然后将新的高频词汇存入另一个词库字符串中,将高频词汇对应的频度存入新的频度数组中。(2)关于排序算法,这里对两个数组同时采用快速排序算法。算法思路是:比如:strings=”英语数学语文化学历史”//五个词语Inta[10]={3,2,5,7,9}Intb[10]={0,1,2,3,4};a存的是每个词的频度,b存的是a中各频度的位置,因为每个频度对应每个词语的位置,如果直接对a排序,将丢失对应关系。这里,采用对a,b数组同时使用快速排序,这样,排序后频度对应的单词位置也不会丢失。最后采用以下语句即可正确实现排序输出:

cout<<"j:"<<j<<""<<s.substr(b[j]*4,4)<<""<<a[j]<<endl;同时,将相应结果输出到输出文件ak48.txt中。系统测试实验输入文档:Ci.txt实验输出文档:ak58.txt程序中可以实现程序控制的常量:

constlongalength=100控制程序扫描到文档哪一位置(扫描字符(即半个汉字)数量)constlongmincipin=2控制单词的最小频度以筛选高频词汇constlongmaxnum=100控制参与快速排序的单词数量(即最后显示数量)以减少算法复杂度constintdancil=2控制单词的字长,为2表示统计两个字的词语通过修改以上四个变量即可实现系统测试。系统评估主要采用系统运行时间和频度的准确性进行评估。系统演示与分析对系统演示结果进行说明,测试一些课程中演示的样例,根据结果说明为什么对或者为什么错。最后对系统提出改进方案(1)统计单字统计双字(2)针对Ci进行一半文档的测试结果令alength=200000,程序运行时间:约8分钟,可读取一半文档约1.5M(3)测试结果分析当然,程序不仅可以统计单字和双字,还可以统计三个字或更多的字组成的词。效率分析:在统计数量较少的文本时,如只统计200的词频时,程序可以达到较好的处理速度,但如果处理长达200000个单词的词频时,程序的效率就显得十分低下了,需要长达8分钟的时间才能统计完毕。准确性分析:

由于程序只针对中文文档进行处理,所以如果遇到英文字符或其他字符,程序将无法识别出来并导致严重的错误,而且在上边(2)的测试结果中,“映□”一词并非文本中真正存在的词汇,而是一个乱码。这说明程序在处理乱码时也会统计错误。改进方案本程序之所以效率会低,主要原因在于统计词频时,采用的数据类型是字符串,而在字符串中用find函数查找指定字符串的效率是很低的。而且排序算法也影响了整个程序的运行效率。所以,可以考虑采用一种更高效率的数据类型来存储单词,比如第二个实验将会用到的map类库,这个类可以定义一种同时存储字符串和其频度的数据类型,每当从文本中读取到一个单词,他就可以用“wordnum[s]++”这一条语句将s字符串的频度+1,在第一次调用时会自动保存字符串s,在之后如果遇到相同的字符串,也不需要再次寻找了,直接将其对应的频度数组加1就行了。四,附源代码为减少文档长度,采用分三栏的排版方法。源代码使用方法:1.在VS2010中新建项目,选C++控制台工程,文件名任意。2.在打开的cpp文档中全选所有文本,将本代码粘贴进去覆盖。3.保证D:\目录下存在要分词的文本文件,文件名定为Ci(.txt格式)//程序需要VS2010运行环境//cipin.cpp:定义控制台应用程序的入口点。//#include"stdafx.h"//只可读取纯中文文档#include<iostream>#include<fstream>#include<string>#include<iomanip>#include<time.h>usingnamespacestd;//程序成功测试完毕,测试时只需通过修改//最大测试:alength=200000;此时程序运行时间:约8分钟//程序运行到的位置:禁陌清,大约读取了文档一半的内容//全局变量constlongalength=100,mincipin=1,maxnum=100;constintdancil=2;intb[maxnum];//全局变量/**********快速排序算法**********/intpartion(inta[],intp,intr){ //rand srand((unsigned)time(NULL)); inte=rand()%(r-p+1)+p; inttem,tem2; tem=a[e]; a[e]=a[r]; a[r]=tem; tem2=b[e]; b[e]=b[r]; b[r]=tem2; intx=a[r],i=p-1; for(intj=p;j<r;j++){ if(a[j]<=x){ tem=a[i+1]; a[i+1]=a[j]; a[j]=tem; tem2=b[i+1]; b[i+1]=b[j]; b[j]=tem2; i++; } } tem=a[r]; a[r]=a[i+1]; a[i+1]=tem; tem2=b[r]; b[r]=b[i+1]; b[i+1]=tem2; returni+1;}voidQuickSort(inta[],intp,intr){ if(p<r){ intq=partion(a,p,r); QuickSort(a,p,q-1); QuickSort(a,q+1,r); }}/**********快速排序算法**********/voidmain(){//程序开始计时clock_tstart,finish;doubletotaltime;start=clock();//程序开始计时 // 初始化 longcnum=alength;//用cnum表示数组长度 longi,j,ndanci=0,count[alength]; intapaixu[maxnum]; unsignedlongn; longpos=0; for(intk=0;k<cnum;k++)count[k]=1; ifstreamfin("d:\\ci.txt"); ofstreamfou("d:\\ak58.txt",ios::out); if(!fin){ cout<<"Fileopenerror!\n"; return; } stringswhole; stringsdanciwh,sdanci,spaixu; time_tt; // 初始化 while(ndanci<cnum&&!fin.eof()){ fin>>swhole;//该操作符一次读取一段 if(swhole.length()>10){//去除词牌名 // swhole.append(sonepara); n=0; for(;n<=(swhole.length()-2*dancil)&&ndanci<cnum;n=n+2){ if(swhole.substr(n+2*(dancil-1),2)==","||swhole.substr(n+2*(dancil-1),2)=="。"||swhole.substr(n+2*(dancil-1),2)=="、" ||swhole.substr(n+2*(dancil-1),2)=="("||swhole.substr(n+2*(dancil-1),2)=="“"||swhole.substr(n+2*(dancil-1),2)==":" ||swhole.substr(n+2*(dancil-1),2)=="”"||swhole.substr(n+2*(dancil-1),2)==")") { n=n+2*(dancil-1); continue;//跳过隔字前方标点 // cout<<"标点:"<<endl; } sdanci=swhole.substr(n,2*dancil);//从swhole中第n个字符开始,读取之后的4字节即两个汉字 // cout<<sdanci<<endl; pos=sdanciwh.find(sdanci); if(pos==string::npos){ sdanciwh.append(sdanci);//将所有单词存入一个字符串中,读取该字符串必须隔4字节 ndanci++; }else{ count[pos/(2*dancil)]=count[pos/(2*dancil)]+1; } } } } fin.close(); cout<<sdanciwh.substr(sdanciwh.length()-8,8)<<endl;//(测试用)输出最后存入的单词 for(i=0,j=0;(j<ndanci*2*dancil)&&(j/(2*dancil)<cnum)&&i<maxnum;j=j+2*dancil){ if(count[j/(2*dancil)]>mincipin){//控制高频词汇 //cout<<sdanciwh.substr(j,4)<<""<<"j/4:"<<j/4<<""<<count[j/4]<<endl; //fou<<sdanciwh.substr(j,4)<<""<<"j/4:"<<j/4<<""<<count[j/4]<<endl; //若要加上排序算法,可以先将高频词汇统计出来存放于数组中,再针对数组排序 //一个字符串存储高频词汇,数组存储对应的频度(参考排序算法) spaixu=spaixu.append(sdanciwh.substr(j,2*dancil));//高频词转存至spaixu apaixu[i]=count[j/(2*dancil)];//频度转存至apaixu i++; } } //排序 for(j=0;j<i;j++)b[j]=j; QuickSort(apaixu,0,i-1); //排序 if(!fou)return; cout<<"顺序"<<"

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论