贝叶斯文本分类实验

来源:互联网 发布:车双头螺纹编程 编辑:程序博客网 时间:2024/05/17 06:55

这个其实是我数据挖掘 的大作业 :

实验原理

主要是利用朴素贝叶斯对文本进行分类,用TF-IDF 权重进行优化。

实验流程:

1 首先下载搜狗语料库

采用其中的五个类别,分别是,1 – 汽车2 –财经3 — 教育 IT4 — 健康5 — 体育 。其中每个分类的训练文档为1000篇,测试文档为131篇。

2中文分词

利用中科院的分词软件,对所有的文档进行分词。比如 第一个类别下的 10.txt 分词后的结果存储在1_re_10.txt 中 。 分词结果(只列出部分):

/x /x 本报/rz 记者/n 陈雪/nr 频/ag 实习/v 记者/n 唐翔/nr 发自/v 上海/ns

/x /x 一家/n 刚刚/d 成立/vi 两年/m 的/ude1 网络/n 支付/vn 公司/n ,/wd 它/rr 的/ude1 目标/n 是/vshi 成为/v 市值/n 100亿/m 美元/q 的/ude1 上市/vn 公司/n 。/wj

他的结果 后面还可以跟着词性,后面我们我们建立词典的时候,只用名词。

  clip_image002

然后所有的训练文档和 测试 的文档放在同一个目录下,我的程序是 读一个ls .txt的文件来决定处理哪些文件。 我采用每个分类1000-1999 作为训练文档,10-140 作为测试文档。

对于第一个分类来说,1_re_10 到1_re_140 都是测试文档 , 1_re_1000 到1_re_1999是训练文档。

3 建立词典

对所有的文档进行词频统计,并只记录下高于某个times 的词,然后再利用stopword.txt ,去掉一些停用词。这样最后得到一个 dict.txt的文件。dict.txt 的格式是 :词 空格 词频,词典一共有33845 个名词。

  clip_image004

其中可以通过生成dict.txt ,可以手工判断一些词作为新的停用词放到到 stopword中去,再次运行程序 ,下次生成新的dict.txt 就可以去掉了 。

4 利用朴素贝叶斯算法对文本进行分类

bayes 算法 : 假设 d 为任意文档,文档 d 用其含有的特征词来表示,即 d=(t

1,t2,……,tk),k 为文档的特征词数,tj表示文档 d 中的第 j 个特征词,由此得到下式:

clip_image006; 其中, clip_image008 表示分类器预测特征值在类别 cj的文档中发生的概率。

根据贝叶斯定理:

clip_image010

由于 P ( d )对所有类来说都是常数 , 同时有C++ 浮点运算的原因,对于clip_image012 就不用乘法了clip_image014 正比于 clip_image008[1]的和 。

clip_image008[2] 表示分类cj特征词ti 出现的概率 ,那么就是等于 特征词ti出现的频率除以cj分类的总的词数 。

详见tf-idf-nb.cpp :bayes()用来训练训练文本,int getType(string filename ) 返回文件的类别。 下面主要介绍下主代码区。

/*计算 P(ti| cj) count(ti) / count(cj), 该分类下的某个词的

出现的概率 除以 该分类的总的词的数目

因为我各自分类取的文档数是一定的所以 我的p(cj) = 1/N */

for(type = 0 ; type < N ; type ++ )

{

long sizeInt = bMap[type].size();

map<string ,double >::iterator iter ;

for(iter =bMap[type].begin() ; iter != bMap[type].end() ; iter ++ )

{

iter->second = (iter->second + 1.0)/( count_classify[type]) ; //这里就是计算 clip_image008[3]

}

}

while(input >> word)

{

string rc = word.substr(0,word.find("/")) ;

//cout << rc << endl;

for(i = 0 ; i < N ; i ++) /*这个就是对测试文档 累加在每个分类下的概率*/

{

iter = bMap[i].find(rc);

if( iter != bMap[i].end())

result[i] += iter->second;

}

}

但是 使用词频的方法正确率只有73%

5 利用TF-IDF 进行优化

之前使用的朴素贝叶斯,使用的是词频权重,这个对文本预处理的依赖性很强。然后我在网上搜索改进方法,使用TF-IDF 作为新的权重计算方法。

clip_image017 ,就是在计算 clip_image008[4] 的时候 ,再乘上这个权重。这个IDF权重。

N 表示文档总数,N(tk)表示包含词 tk的文档数。IDF 的值越大,说明包含该特征词的文档越少,那么这个特征词分布得就相对集中,则这个特征词有可能包含更多的类别信息;相反,如果 IDF 的值比较小,则说明这个特征词在文档集中分布得相对均匀,对文档的分类没有多大贡献,该词不适合作为分类的特征。

相应在代码中的修改如下表:

while(input >> word)

{

string rc = word.substr(0,word.find("/")) ;

//cout << rc << endl;

for(int i = 0 ; i < N ; i ++)

{

iter = bMap[i].find(rc);

if( iter != bMap[i].end() && dictMap.find(rc) != dictMap.end() )

{

if( weightMap.find(rc) != weightMap.end() )

result[i] += (iter->second * (log( documentN / (weightMap.find(rc)->second) ) ) ) ;

else

cout << "can not find " << rc << "in weightMap" << endl;

}

}

}

实验结果为:

clip_image020

这里我用数字代表分类,一共五个类别,5 5 表示第5个类别的文档,然后用改进后的算法计算之后的的类别。下面简单的统计了每个分类的正确率,和整体的正确率。


原始博客地址