基于Ruby和中文分词的贝叶斯反垃圾解决方案

贝叶斯过滤技术是非常有效的反垃圾技术。在Ruby中,有几个Library实现了贝叶斯过滤,可惜的是它们都不支持中文分词。而mmseg则是比较流行的中文分词技术,在Ruby框架下,有rmmseg这个Library实现了mmseg分词法并自带了词库,非常方便。本文将这两种技术结合在一起,使得在Ruby下可以获得支持中文的贝叶斯过滤器。安装及试用classifier首先来通过简单的使用来熟悉一下贝叶斯反垃圾引擎,这里我们使用的gem叫做classfier,项目地址位于 “https://github.com/kitop/classifier”:https://github.com/kitop/classifier使用gem命令安装这个library:

sudo gem install classifier -v=1.3.3Password:Successfully installed classifier-1.3.31 gem installedInstalling ri documentation for classifier-1.3.3...Installing RDoc documentation for classifier-1.3.3...

为了方便说明,所以明确指定了使用1.3.3这个版本。但是这个版本有一个BUG,因此我们需要打个补丁。找到gem的安装目录:

gem list -d classifier[b]*[/b]LOCAL GEMS[b]*[/b]classifier (1.3.3)    Author: Lucas Carlson    Homepage: http://classifier.rufy.com/    Installed at: /Library/Ruby/Gems/1.8    A general classifier module to allow Bayesian and other types of    classifications.

我的gem位于/Library/Ruby/Gems/1.8, 因此我进入这个目录,找到gems子目录,里面应该有classifier-1.3.3/找到lib/classifier/bayes.rb这个文件,在45行下面添加一行代码:

orig ||= 0

修改后代码如下所示:这样,我们便装好了这个gem,打开irb玩玩看:

irb >> require 'classifier'=> true>> checker = Classifier::Bayes.new('spam', 'not spam')=> #<Classifier::Bayes:0x1010e9cd0 @total_words=0, @categories={:Spam=>{}, :"Not spam"=>{}}>>> checker.train :not_spam, "It's a good day!"=> {:"!"=>1, :it=>1, :"'"=>1, :good=>1, :dai=>1}>> checker.train :spam, "buy buy buy!"=> {:"!"=>1, :bui=>3}>> checker.classify "What a lovely day~"=> "Not spam">> checker.classify "Buy some apple?"=> "Spam">> 

可以看到贝叶斯引擎的原理是将句子拆分成词,并根据词频来进行归类判断,因此样本数量越大判断越准确。通过上面的例子,我们可以看到classifier这个库是通过自然空格对英文句子进行断句分词,很遗憾这种方式并不适用于中文。classfier与中文的不兼容性我们通过一个例子来说明classifier与中文的不兼容性。首先创建一个txt文档,写入一些中文,可将文件保存为sample.txt:sample.txt

人类在社会发展中,对于自然世界的认识和精神世界里的追求,源远流长,形成了巨大的精神财富,如文学、艺术、教育、科学等,这些以文字或符号加以记载和传播,就形成了我们所说的文化。历史上,尽管各民族的文化差异很大,但一项重大的科学成就,常常能够影响整个世界文化发展的进程。

进入irb终端,试着将classfier应用于这段文字:

 irb>> require 'classifier'=> true>> checker = Classifier::Bayes.new('spam', 'not spam')=> #<Classifier::Bayes:0x1010e9c30 @total_words=0, @categories={:Spam=>{}, :"Not spam"=>{}}>>> File.open('sample.txt').each_line{ |s| p checker.train :not_spam, s>>  }{:"\344\272\272\347\261\273..."=>1}=> #<File:sample.txt>>> 

可以看到,classifier只生成了一个词频为1的大字串,把全段文字当成是一个单词保存了起来,这段文字并没有被正确地拆成中文词语并进行正确的词频统计。原因在于classfier仅内置了英文的拆词法,即通过空格来拆分单词,这样的方式显然是无法用于中文的,因此为了能让中文内容也用上classifier库,我们首先要做的是使其能将中文段落正确的拆成词,RMMSeg的用处就在这里。RMMSeg的安装及使用而mmseg是很流行的中文分词算法,在ruby下有中文分词器的实现RMMSeg,使用它的好处是它完全用ruby实现,并且自带词库,十分方便。我们先来了解一下如何使用这个分词器,首先是用gem来安装它:

sudo gem install rmmseg

成功安装后,我们仍然可以通过IRB试用下这个library。进入irb终端,测试一下RMMSeg是否可以正常工作,仍然使用前面创建的中文文件sample.txt来做测试:

 irb>> require 'rmmseg'=> true>> include RMMSeg=> Object>> File.open('sample.txt').each_line{ |s| p segment(s) }["人类", "在", "社会", "发展中", ",", "对于", "自然", "世界", "的", "认识", "和", "精神世界", "里", "的", "追求", ",", "源远流长", ",", "形成", "了", "巨大", "的", "精神", "财富", ",", "如", "文学", "、", "艺术", "、", "教育", "、", "科学", "等", ",", "这些", "以", "文字", "或", "符号", "加以", "记载", "和", "传播", ",", "就", "形成", "了", "我们", "所说", "的", "文化", "。", "历史上", ",", "尽管", "各民族", "的", "文化", "差异", "很大", ",", "但", "一项", "重大", "的", "科学", "成就", ",", "常常", "能够", "影响", "整个", "世界文化", "发展", "的", "进程", "。"]=> #<File:sample.txt>

可以看到,通过RMMSeg的segment命令,一段中文文字被切成了词。接下来的工作,是改造classifier库的断字部分,让它使用RMMSeg提供的中文断字能力。改造classifier,集成RMMSeg,使之支持中文分词classifier的分词代码位于其函数库根目录的lib/classifier/extensions/word_hash.rb中。我们打开这个文件,在代码一开始添加:

require 'rmmseg'include RMMSeg

然后找到word_hash这个函数,将基于空格的分词方法改成RMMSeg给出的segment方法进行分词:

def word_hash#word_hash_for_words(gsub(/[^\w\s]/,"").split + gsub(/[\w]/," ").split)word_hash_for_words(segment(gsub(/[^\w\s]/,"")) + gsub(/[\w]/," ").split)end

修改后的代码如下所示:改造完成后,我们便可以用刚才的sample.txt重新做下测试,看看classifier是否可以针对中文正常工作了:

irb>> require 'classifier'=> true>> checker = Classifier::Bayes.new('spam', 'not spam')=> #<Classifier::Bayes:0x10109c318 @categories={:Spam=>{}, :"Not spam"=>{}}, @total_words=0>>> File.open('sample.txt').each_line{ |s| p checker.train :not_spam, s>> }{:重大=>1, :我们=>1, :科学=>2, :源远流长=>1, :发展中=>1, :世界文化=>1, :各民族=>1, :符号=>1, :如=>1, :认识=>1, :成就=>1, :所说=>1, :等=>1, :形成=>2, :,=>9, :发展=>1, :差异=>1, :加以=>1, :文学=>1, :和=>2, :常常=>1, :文化=>2, :这些=>1, :了=>2, :对于=>1, :进程=>1, :很大=>1, :记载=>1, :、=>3, :精神世界=>1, :人类=>1, :能够=>1, :。=>2, :以=>1, :巨大=>1, :自然=>1, :但=>1, :传播=>1, :艺术=>1, :里=>1, :在=>1, :影响=>1, :历史上=>1, :文字=>1, :精神=>1, :世界=>1, :一项=>1, :就=>1, :教育=>1, :追求=>1, :社会=>1, :整个=>1, :尽管=>1, :或=>1, :财富=>1, :的=>7}=> #<File:sample.txt>>> 

可以看到,中文被正确地拆分并加以词频统计了。我们得到了一个支持中文的贝叶斯反垃圾引擎。试用支持中文的classifier接下来可以玩玩看classifier是否能正确区分开垃圾内容非垃圾内容了,我们分别创建一个垃圾内容样本spam.txt及非垃圾内容样本not_spam.txt:spam.txt

咆哮体!伤不起!这就是咆哮体!!啊啊!!啊啊!!!有木有!!!有木有啊!!!!! 

not_spam.txt

人类在社会发展中,对于自然世界的认识和精神世界里的追求,源远流长,形成了巨大的精神财富,如文学、艺术、教育、科学等,这些以文字或符号加以记载和传播,就形成了我们所说的文化。历史上,尽管各民族的文化差异很大,但一项重大的科学成就,常常能够影响整个世界文化发展的进程。

接下来创建一个待分检垃圾样本test.txt:test.txt

老子两年前选了法语课!!!!!!!!于是踏上了尼玛不归路啊!!!!!!!!!!谁跟老子讲法语是世界上最油煤的语言啊!!!!!!!!尼玛听的哪个外太空的法语啊!!!!!!!!!!!跟吐痰一样一样一样的啊 有木有!!!!!!!!!谁再跟老子讲法语是世界上最油煤的语言 老子一口浓痰咸死你啊!!!!!!!!!!!!!!! 

我们会将spam.txt里面的内容标记为垃圾内容,将not_spam.txt里面的内容标记为非垃圾内容。而test.txt里面的内容是待测试内容,我们期待的结果是classifier将其识别为垃圾内容,即Spam。下面是测试过程及结果:

 irb>> require 'classifier'=> true>> checker = Classifier::Bayes.new('spam', 'not spam')=> #<Classifier::Bayes:0x10109c1d8 @categories={:Spam=>{}, :"Not spam"=>{}}, @total_words=0>>> File.open('spam.txt').each_line{ |s| p checker.train :spam, s }{:伤=>1, :木=>2, :不起=>1, :这就=>1, :咆哮=>2, :是=>1, :体=>2, :啊=>5, :!=>17, :有=>4}=> #<File:spam.txt>>> File.open('not_spam.txt').each_line{ |s| p checker.train :not_spam, s }{:重大=>1, :我们=>1, :科学=>2, :源远流长=>1, :发展中=>1, :世界文化=>1, :各民族=>1, :符号=>1, :如=>1, :认识=>1, :成就=>1, :所说=>1, :等=>1, :形成=>2, :,=>9, :发展=>1, :差异=>1, :加以=>1, :文学=>1, :和=>2, :常常=>1, :文化=>2, :这些=>1, :了=>2, :对于=>1, :进程=>1, :很大=>1, :记载=>1, :、=>3, :精神世界=>1, :人类=>1, :能够=>1, :。=>2, :以=>1, :巨大=>1, :自然=>1, :但=>1, :传播=>1, :艺术=>1, :里=>1, :在=>1, :影响=>1, :历史上=>1, :文字=>1, :精神=>1, :世界=>1, :一项=>1, :就=>1, :教育=>1, :追求=>1, :社会=>1, :整个=>1, :尽管=>1, :或=>1, :财富=>1, :的=>7}=> #<File:not_spam.txt>>> File.open('test.txt').each_line{ |s|  p checker.classify s }"Spam"=> #<File:test.txt>>> 

可以看到,test.txt中的内容按照预期被识别为垃圾内容。参考资料http://www.iteye.com/news/1380 – robbin写的rmmseg介绍https://github.com/logankoester/classifier – classifier项目网址 http://rmmseg.rubyforge.org/ - rmmseg文档http://baike.baidu.com/view/4169613.htm – 咆哮体 大小: 45.2 KB 大小: 53.2 KB 大小: 50.7 KB 查看图片附件 而在于当时的那份心情。可是旅行的彼时那刻我的心情一直是好的吗?

基于Ruby和中文分词的贝叶斯反垃圾解决方案

相关文章:

你感兴趣的文章:

标签云: