兔纸张

It is the time you have wasted for your rose that makes your rose so important.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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 )

posted on 2011-07-20 22:54  geiliCode  阅读(523)  评论(0编辑  收藏  举报