一种没有语料字典的分词方法

标签: 没有 字典 分词 | 发表时间:2013-05-14 16:38 | 作者:ygrx
出处:http://blog.csdn.net
前几天在网上闲逛,看到一篇美文,说的是怎么在没有语料库的情况下从文本中提取中文词汇,理论部分讲得比较多,但都还是很浅显易懂的,其中涉及一部分信息论的理论,其实只要大学开过信息论这门课的话,看起来还是挺简单的。

信息论我忘得差不多了,但是其中主要的内容还记得,信息论最主要的就是信息其实是可以度量的,一个事件包含的信息和它发生的概率成反比,简单的说,同样一个事件,产生A结果的概率为Pa,产生B结果的概率为Pb,如果Pa大于Pb,那A所包含的信息量就比B要大。

打个简单的比喻,比如中国队和西班牙队踢足球比赛,大家都知道,西班牙队赢的概率大概是99.9999%,中国队赢的概率大概是0.0001%,假如最后的结果是中国队赢了(靠实力)的话,那这个事件(中国队赢了西班牙)就是个信息量非常巨大的事件,我相信各大报纸的头条都会报道,反而如果西班牙赢了,估计没有报纸会报道这个消息,这就是信息论的核心,也就是信息熵。

扯远了,上面只是说说我对信息论的理解,在分词技术上,目前的分词技术基本上都是基于字典的,就是看文章中有没有字典含有的词语,如果有,就把这个当成一个词来分,这样也衍生了很多分词技术,大家有兴趣可以自己去查一查。

如果我们没有词典,需要分词就比较麻烦了,假设我们最大的词长度设定为5,能想到的办法就是,从第一个字开始,把文本中所有连在一起的两个字,三个字,四个字,五个字的片段找出来,然后看这些片段在文本中出现的频率,频率高的就当成一个词汇,这样确实能分出词来,但是这样同样也分出了一些不是词的词汇,比如上面的文章中,“的话”这个词就出现的相对比较多,显然,这不是一个词。

在这种基础上怎么把类似“的话”这样的词去掉就是我们要做的工作了。这涉及到两个重要的部分,也是那篇美文提到的两个部分。

第一,怎么去掉类似于“的中国”和“中国队”这样的差异,这三个词可能出现的频率都差不多,甚至“的中国”出现的频率更高,假设对于一个长文本(假设为10000,并且是描述足球比赛的),
“的中国”出现了100次,概率是1%
“中国队”出现了60次,概率是0.6%
“中国”   出现了200次,概率为2%
“的”       出现了500次,概率为5%
“队”       出现了70次,概率为0.7%
这样的数据情况下,“的”字和“中国”随机组合在一起的概率为5%*2%=1%,而“队”和“中国”随机组合在一起的概率为0.7%*2%=0.14%,显然“的中国”的出现概率和他们组合在一起的概率差不多,所以我们认为“的中国”更像是随机组合在一起的词而不是一个固定的词汇,但“中国队”出现的概率比他们组合在一起的概率高了4.28倍,所以我们认为“中国队”更像一个词汇。
通过上面的计算,我们就可以把“的中国”这样的词丢掉了,就算他出现了很多次,但是我们一样不认为它是一个词,这就是第一部分,我们把它叫词语的凝聚程度,“的中国”显然凝聚力不够。


第二,像类似“了一”这样的词在文章中肯定也出现得很多,因为是足球比赛文章,所以经常出现摔了一跤,进了一球等等,显然,“了一”也不是一个词汇,但是单独看“了”和“一”,“了一”的概率可能比他们单独组合的概率高不少,像这样的词怎么弄呢,这就要用到开头我们讲的信息论中的信息熵了。

“信息熵”能够反映知道一个事件的结果后平均会给你带来多大的信息量。如果某个结果的发生概率为 p ,当你知道它确实发生了,你得到的信息量就被定义为 - log(p) 。 p 越小,你得到的信息量就越大。在“了一”这个词中,他的前缀为“摔”,“进”,概率分别是p1,p2那他的前缀信息熵就是- log(p1)*p1-log(p2)*p2,同样后缀的信息熵也可以算出来,算出来以后我们取其中较小的那个作为这个词的前后缀信息熵,结果算出来是一个非常小的数,比如0.2,比普通真实的词汇,比如“摔了一跤”这样的词的信息熵都要小,所以显然可能“了一”就不是一个词汇了,反而“摔了一跤”这样的词更像一个词汇。

有了这两个理论,那我们找出一个词,然后按这两个条件给出一个阈值,就能抽取出一批我们认为是词汇的词语了,不需要字典,而且从抽取出来的词根据词频排列的话,再把一般性的词如“应该”,“如果”,“似乎”这样的介词去掉的话,一般是这个文本的关键字集合了。

嗯,理论部分大概就是这样了,具体的大家要是有兴趣,可以看看这篇blog,我都是看到这个的,顺便推荐一个这个作者,他的文章基本上都是原创,而且对数学理解得很到位,很适合各种程序猿们,呵呵。

按照这个东西,我自己写了个python脚本,写得很着急,而且不知道理论理解得对不对,后来我对《明朝那些事》抽了一把,出现了这些:
危险 优秀沉默李景隆 影响 杨继盛 痛苦 脑袋 徐有贞厉害支持 蓝玉杨廷和瓦剌 申时行 判断 记载 孙承宗坚持愤怒 奏疏 锦衣卫 严世蕃 祁钰 倭寇 东林党麻烦 朋友 努尔哈赤  选择喜欢 容易 首辅 御史李如松父亲戚继光 投降 陈友谅 厚照 希望 蒙古 简单估计消息 彻底 胡宗宪 祁镇毕竟魏忠贤告诉袁崇焕嘉靖似乎准备。。。。。。。。

而对于《时间简史》,出现了这些:
空间时间 吸引增加基本 尺度 效应 东西描述轨道
位置 边界产生解释 夸克 广义相对论 坍缩 辐射 部分
知道 状态区域距离 爆炸 问题 奇点模型太阳
事件 科学预言运动 膨胀 任何 必须恒星黑洞 .......

你修改约束条件,就会出现不同的词语,怎么平衡这个约束条件也是个问题。

另外,如果你有兴趣,可以分析分析一些人的blog和微博之类的,再和你自己的对比一下,说不定能找到很多关键词一样哦,还有,要是你有海量的数据,也可以做一些非常有意思的事情哦,哈哈。


最后,再次推荐一下matirx67的blog:   http://www.matrix67.com/     


程序做得太快了,不好,还是把关键函数贴出来吧,就是暴力的编码,用了python自带的方便的数据结构来快速开发。所以速度上比较慢,而且内存上。。呵呵。。说不定会爆哦。。。。完整程序:
https://github.com/wyh267/ChineseWordSegmentation

# -*- coding=utf-8 -*-
'''
Created on 2013-5-9

@author: Wu YingHao

@email:  [email protected]

该程序可以在没有语料库的情况下从文本中抽取出中文词汇
理论支持:
http://www.matrix67.com/blog/archives/5044

'''


import math


"""
    计算每个字和词的出现频率
    输入: words 字符串内容
      num 需要截取的最长字串
    输出: split_words 分割好的所有子串的数据,以字典形式返回
      split_words 说明
      {"字串" : [ 出现次数,出现概率,凝固程度,凝固程度*出现次数,自由程度,前缀集合,后缀集合] .....}
"""
def find_words(words,num=6):
    split_words={}
    lens=len(words)
    for i in range(0,lens):
        for j in range(1,num+1):
            if i+j < lens -num-2:
                if words[i:i+j] in split_words:
                    split_words[words[i:i+j]][0]+=1
                    split_words[words[i:i+j]][1]=float(split_words[words[i:i+j]][0])/float(lens)
                    split_words[words[i:i+j]][6].append(words[i-1])
                    split_words[words[i:i+j]][7].append(words[i+j])
                else:
                    split_words[words[i:i+j]]=[1,
                                               1/float(lens),
                                               words[i:i+j],
                                               1,
                                               1,
                                               0,
                                               [words[i-1]],
                                               [words[i+j]]
                                               ]
                    
                                               
        if(i%10000==0):
            print "完成 :" + str(float(i)/float(len(words))*100) + " %"
                
    return split_words
                


"""
    计算凝聚程度
    输入:words_dic 已经拆分好的字符串字典
    输出:填充好凝聚程度的字典
"""
def find_nh(words_dic):
    for key in words_dic.keys():
        if(len(key)>1):
            #左凝聚程度
            left_p=words_dic[key][1]/(words_dic[key[:1]][1]*words_dic[key[1:]][1])
            #右凝聚程度
            right_p=words_dic[key][1]/(words_dic[key[:-1]][1]*words_dic[key[:-1]][1])
                 
            
            if(left_p<right_p):
                words_dic[key][3]=left_p
            else:
                words_dic[key][3]=right_p
    



"""
    计算自由程度
    输入: word_dic 字典文件
    返回:word_dic 添加自由程度以后的字典
"""
def calc_free(word_dic):
    for key in word_dic.keys():
        front_free=0
        end_free=0
        for front in word_dic[key][6]:
            if front in word_dic:
                front_free-=math.log(word_dic[front][1])*word_dic[front][1]
        
        for end in word_dic[key][7]:
            if end in word_dic:
                end_free-=math.log(word_dic[end][1])*word_dic[end][1]
            
        if(front_free < end_free):
            word_dic[key][5]=front_free
        else:
            word_dic[key][5]=end_free

    return word_dic
    


注:本文虽然不是转帖,但是内容参考了matrix67的博客,地址为   http://www.matrix67.com/blog/archives/5044  ,特此声明。



作者:ygrx 发表于2013-5-14 16:38:25 原文链接
阅读:64 评论:0 查看评论

相关 [没有 字典 分词] 推荐:

一种没有语料字典的分词方法

- - CSDN博客架构设计推荐文章
前几天在网上闲逛,看到一篇美文,说的是怎么在没有语料库的情况下从文本中提取中文词汇,理论部分讲得比较多,但都还是很浅显易懂的,其中涉及一部分信息论的理论,其实只要大学开过信息论这门课的话,看起来还是挺简单的. 信息论我忘得差不多了,但是其中主要的内容还记得,信息论最主要的就是信息其实是可以度量的,一个事件包含的信息和它发生的概率成反比,简单的说,同样一个事件,产生A结果的概率为Pa,产生B结果的概率为Pb,如果Pa大于Pb,那A所包含的信息量就比B要大.

新话字典

- tiancaicai - 南方周末-热点新闻
从1953年至今57年,《新华字典》发行逾4亿册,无论从发行量、普及面、影响程度,还是读者忠诚度来看,它对中国人的意义类似于圣经之于基督徒. 而它营造的新话系统也成为我们挥之不去的烙印.

Google关闭字典服务

- Johnson - Solidot
Google在没有给出任何预警的情况下突然关闭了字典服务. Google建议用户“通过 Google 网页搜索查找相关定义,或通过 Google 翻译来翻译相关内容”. Google字典最初Google 翻译的一部分,后成为一项独立服务. 与Google 翻译相比,Google字典提供了更丰富的语义解释、示例,并提供了来自外部来源如维基百科的链接.

iOS 5 的內建字典

- chitsaou - applewoods&#39;s posterous
Apple 在 10 月 12 日正式釋出 iOS 5 供使用者進行升級,新增了超過 200 項大大小小的新功能,像是通知中心、iMessage、書報攤、提醒事項、相機...等等. 而還有一個比較少被留意到的是其內建的字典功能,也是我們最喜愛的新增項目之一,這個可在系統中隨處取用的字典十分方便,只要點一下並按住單字 (有出現文字的地方應該都可以,如電子郵件、備忘錄、Safari 網頁、Twitter 等等),然後點一下「定義」,字典便會秀出單字定義了.

java中文分词组件-word分词

- - 研发管理 - ITeye博客
关键字:java中文分词组件-word分词. word分词器主页 :https://github.com/ysc/word. word分词是一个Java实现的中文分词组件,提供了多种基于词典的分词算法,并利用ngram模型来消除歧义. 能准确识别英文、数字,以及日期、时间等数量词,能识别人名、地名、组织机构名等未登录词.

偷用被關閉的 Google 字典

- 葱八 - T客邦
Google 官方將字典服務下架以後,當我們看到不認識的英文單字,想要查它的解釋及用法時就顯得更麻煩了,當然還可以安裝其他字典軟體來使用,不過Google字典還蠻好用的,關閉起來實在很可惜,我們可利用網友製作的 Google 字典介面,讓字典服務完全重生. 官方網址:http://dictionary.grassboy.tw/.

Kindle4 中如何设置字典

- yanbook - Page to Page
Kindle4上更换默认字典的方式和以前有了改变,而且在调用字典上也有变化. 更换字典需要到设置页中完成,另一方面,字典的语言必须和书籍对应,否则不会翻译. 可以看到Amazon在多语言下做的努力,或许不久就会推出中文语言和字典支持. 原来的字典要使用在Kindle4上,需要做一点小修改. 由Home 页面,按menu键 选择Settings,翻到设置页的第二页,用5向键选择Dictionaries.

lucene字典实现原理 - zhanlijun

- - 博客园_首页
      使用lucene进行查询不可避免都会使用到其提供的字典功能,即根据给定的term找到该term所对应的倒排文档id列表等信息. 实际上lucene索引文件后缀名为tim和tip的文件实现的就是lucene的字典功能.       怎么实现一个字典呢. 我们马上想到排序数组,即term字典是一个已经按字母顺序排序好的数组,数组每一项存放着term和对应的倒排文档id列表.

Facebook:Google+没有用户

- Nanqi - 36氪
6月份 Google 推出带视频群聊的社交网络 Google+ 之后,Facebook 马上联合 Skype 推出基于网页版的一对一视频聊天服务,上周 Google 宣布推出 Google+ 上的社交游戏平台,并首先上线了《愤怒的小鸟》、Zynga 的《德州扑克》等游戏之后,Facebook 马上回应对游戏进行了一系列的改版,包括游戏分辨率更高,侧边栏 News Feed 等.

如果没有 Linux ……

- Iceberg - LinuxTOY
收藏到 del.icio.us |.