3. 中文分词
虽然中文分词工具也很多,但没有一个分词工具能像ICTCLAS那样光芒万丈,而且还是免费的,所以就直接用它了。
我们先看下ICTCLAS犀利的简介 :
- ICTCLAS在国内973专家组组织的评测中活动获得了第一名,在第一届国际中文处理研究机构SigHan组织的评测中都获得了多项第一名。
- ICTCLAS 2011分词速500KB/s左右,分词精度98.45%,API不超过100KB,各种词典数据压缩后不到3M。
- ICTCLAS全部采用C/C++编写,支持Linux、FreeBSD及Windows系列操作系统,支持C/C++/C#/Delphi/Java等主流的开发语言
单击此处,可以获得ICTCLAS更详细的介绍,想膜拜该作者的童靴可以去新浪微博围观@ICTCLAS张华平博士
使用C#的同学可以从网站上下载 ICTCLAS2011_Windows_32_c ,其中有详细介绍C#接口的文档和Demo.
添加好C#的接口之后,就可以用如下函数进行分词:
ICTCLAS clas = ICTCLAS.GetInstance(); List<ResultTerm> terms = clas.Segment(str);
其中str是string类型的待分词文本,返回的结果中ResultTerm的结构如下:
public struct ResultTerm { public string Word; //字符串 public int POS; //词性标志 public string POSStr; //词性说明 }
可以看出,分词返回的结果中并没有词频,这个需要我们自己统计。
在之后计算相似度的过程中,发现去除停用词和只保留词频和字数都大于1的词项后得到的结果,与使用全部词项的结果差不多,所以在分词时就只保留了部分有代表性(非停用词且词频和字数都大于1)的词项,并将剩余的词项按词频降序排序。
分词部分的实现代码如下:
class TermFrequence { private string[] stopWords; //停用词表 private BaikeEntry baikeEntry; private TermFrequence() { } public TermFrequence(BaikeEntry newBaikeEntry) { baikeEntry = newBaikeEntry; GetTermDic(); RemoveStopWords(); GetTermList(); //只保留词频大于1且词项字数大于1的词项 UpdateTermDic(); GetTermShow(); } private void GetTermDic() { ICTCLAS clas = ICTCLAS.GetInstance(); List<ResultTerm> terms = clas.Segment(baikeEntry.text); baikeEntry.wordDic.Clear(); foreach (ResultTerm term in terms) { if (baikeEntry.wordDic.ContainsKey(term.Word)) baikeEntry.wordDic[term.Word] += 1; else baikeEntry.wordDic.Add(term.Word, 1); } } private void RemoveStopWords() { //获取停用词表 StreamReader sr = new StreamReader("stopWords.txt", Encoding.UTF8); string tmp = sr.ReadToEnd(); stopWords = Regex.Split(tmp, @"\r\n"); //去除停用词 foreach (string str in stopWords) { if (baikeEntry.wordDic.ContainsKey(str)) baikeEntry.wordDic.Remove(str); } //去除其他字符 Dictionary<string, int> newDic = new Dictionary<string, int>(); foreach (KeyValuePair<string, int> dic in baikeEntry.wordDic) { if (Regex.Replace(dic.Key, @"(?is)\s*", "").Length != 0) newDic.Add(dic.Key, dic.Value); } baikeEntry.wordDic = newDic; } private void GetTermList() { baikeEntry.wordList.Clear(); foreach (KeyValuePair<string, int> dic in baikeEntry.wordDic) { if (dic.Value > 1 && dic.Key.Length > 1) baikeEntry.wordList.Add(new WordFreq(dic.Key, dic.Value)); } baikeEntry.wordList.Sort((a, b) => { return b.freq - a.freq; }); } private void UpdateTermDic() { baikeEntry.wordDic.Clear(); foreach (WordFreq wf in baikeEntry.wordList) baikeEntry.wordDic.Add(wf.name, wf.freq); } private void GetTermShow() { foreach (WordFreq wf in baikeEntry.wordList) baikeEntry.allWordFreq += string.Format("{0}:{1}\n", wf.name, wf.freq); } }
-------------------------------------------
作者:兔纸张 来源:博客园 ( http://www.cnblogs.com/geiliCode )