在使用贝叶斯算法分类文本时,中文处理是个头疼的问题,这主要体现在中文分词上。所谓分词的意思就是让计算机能够拆分出一句话中的词,比如把“我们爱祖国”分为“我们”、“爱”和“祖国”,这是简单的情况,更复杂比如把“变态性心理”按上下文语境分别拆分为“变态性”“心理”和“变态”“性心理”[1]。由于词的定义、分词标准和词的判定都没有一个统一的共识,再加上计算机在处理语义上的困难,因此“汉语自动分词已经被研究了二十多年,但是目前仍然是制约汉语信息处理发展的一个瓶颈”[2]。目前公认的比较好的分词技术,来源于中科院计算所的“汉语词法分析系统ICTCLAS”,它提供了Windows和Linux平台下C#、C和Java JNI的API。
不过本文并非讨论分词技术,因为这项技术本身已经超越了目前LT的需求。实际上,我们只要对b8做一些改动,让它在拆分文本时考虑到双字节字符(比如中文)的情况,并在实际拆分时以字为单位,就可以应付一般的情况。
LT从1月24日发布的0.4.4中开始使用改造过的b8贝叶斯算法,从实际运行情况来看,改造后的b8能够比较好的处理中文的情况。另外由于绝大部分SPAM都是英文,因此总的来说中文分字的做法可以接受。
打开b8/lexer/lexer_default.php文件,首先修改lexer_default()这个constructor,在方法的最后添加如下代码:
//set the default encoding for mutil-byte characters mb_internal_encoding('UTF-8');
接着修改getTokens(),第一是提取中文标点符号,在$tokens = "";一行代码下面添加如下代码:
//strip Chinese punctuation $text = preg_replace('/[“”!◎#¥%……※×()——+§『』【】,。、‘’;:~·]/u', '', $text);
第二处理网址和IP地址,找到如下代码:
preg_match_all("/([A-Za-z0-9\_\-\.]+)/", $text, $raw_tokens);
将其修改为:
//exract all Chinese tokens preg_match_all('/[一-龥]/u', $text, $raw_tokens_chinese); //exract all Latin tokens preg_match_all("/([A-Za-z0-9\_\-\.]+)/", $text, $raw_tokens_latin);
将提取出来的中文和拉丁字符合并在一起,组成raw tokens:
$raw_tokens = array_merge($raw_tokens_chinese[0], $raw_tokens_latin[0]);
第三继续提取剩余的中文和拉丁文字符,找到如下代码:
# Raw splitting of the remaining text $raw_tokens = preg_split("/[^A-Za-z0-9!?\$дег'`─╓▄фЎ№▀╔щ╚ш╩ъ┴с└р┬т╙є╥Є╘Ї╟ч]/", $text);
将其修改为:
# Raw splitting of the remaining text //exract all Chinese tokens, split each Chinese character with preg_match_all() preg_match_all('/[一-龥]/u', $text, $raw_tokens_chinese); //delete Chinese characters from the text, extract all Latin tokens $raw_latin = $this->strip_whitespaces(preg_replace('/[一-龥]!?/u', ' ', $text)); $raw_tokens_latin = preg_split("/[^A-Za-z0-9!?\$дег'`─╓▄фЎ№▀╔щ╚ш╩ъ┴с└р┬т╙є╥Є╘Ї╟ч]/", $raw_latin); //merge Chinese tokens and Latin's $raw_tokens = array_merge($raw_tokens_chinese[0], $raw_tokens_latin);
然后修改isValid(),找到如下代码:
# Check for a proper length if(strlen($token) config['minSize'] or strlen($token) > $this->config['maxSize']) return FALSE;
将其修改为:
# Check for a proper length //only when the token is NOT Chinese we need to do the check if(!preg_match('/[一-龥]/u', $token)) { if(strlen($token) config['minSize'] or strlen($token) > $this->config['maxSize']) return FALSE; }
至此b8的中文化改造和本系列文章都完成了,你可以试试效果:),抵御SPAM这块我也接触不久,有问题欢迎讨论。
文中的一些标注:
請問可否分享修改後的檔案 ?
@Bii 已经邮件发给你了。 [emoticon:clin_oeil]
好像我改后不行,因为文件的编码我看到是unix下的ASC编码,而你添加的是utf编码,是不是要写一个PHP header,然后把文件的编码改成UTF-8呢?你有没有单独的B8改好了的?我想看看...谢谢
麻烦分享下修改过的代码,谢谢。