漫话中文分词

出处:http://www.matrix67.com/blog/archives/4212

漫话中文自动分词和语义识别(上):中文分词算法

记得第一次了解中文分词算法是在 Google 黑板报 上看到的,当初看到那个算法时我彻底被震撼住了,想不到一个看似不可能完成的任务竟然有如此神奇巧妙的算法。最近在詹卫东老师的《中文信息处理导论》课上再次学到中文分词算法,才知道这并不是中文分词算法研究的全部,前前后后还有很多故事可讲。在没有建立统计语言模型时,人们还在语言学的角度对自动分词进行研究,期间诞生了很多有意思的理论。

中文分词的主要困难在于分词歧义。“结婚的和尚未结婚的”,应该分成“结婚/的/和/尚未/结婚/的”,还是“结婚/的/和尚/未/结婚/的”?人来判断很容易,要交给计算机来处理就麻烦了。问题的关键就是,“和尚未”里的“和尚”也是一个词,“尚未”也是一个词,从计算机的角度看上去,两者似乎都有可能。对于计算机来说,这样的分词困境就叫做“交集型歧义”。

有时候,交集型歧义的“歧义链”有可能会更长。“中外科学名著”里,“中外”、“外科”、“科学”、“学名”、“名著”全是词,光从词库的角度来看,随便切几刀下去,得出的切分都是合理的。类似的例子数不胜数,“提高产品质量”、“鞭炮声响彻夜空”、“努力学习语法规则”等句子都有这样的现象。在这些极端例子下,分词算法谁优谁劣可谓是一试便知。

最简单的,也是最容易想到的自动分词算法,便是“最大匹配法”了。也就是说,从句子左端开始,不断匹配最长的词(组不了词的单字则单独划开),直到把句子划分完。算法的理由很简单:人在阅读时也是从左往右逐字读入的,最大匹配法是与人的习惯相符的。而在大多数情况下,这种算法也的确能侥幸成功。不过,这种算法并不可靠,构造反例可以不费吹灰之力。例如,“北京大学生前来应聘”本应是“北京/大学生/前来/应聘”,却会被误分成“北京大学/生前/来/应聘”。

维护一个特殊规则表,可以修正一些很机械的问题,效果相当不错。例如,“不可能”要划分成“不/可能”,“会诊”后面接“断”、“疗”、“脉”、“治”时要把“会”单独切出,“的确切”后面是抽象名词时要把“的确切”分成“的/确切”,等等。

还有一个适用范围相当广的特殊规则,这个强大的规则能修正很多交集型歧义的划分错误。首先我们要维护一个一般不单独成词的字表,比如“民”、“尘”、“伟”、“习”等等;这些字通常不会单独划出来,都要跟旁边的字一块儿组成一个词。在分词过程中时,一旦发现这些字被孤立出来,都重新考虑它与前面的字组词的可能。例如,在用最大匹配法切分“为人民服务”时,算法会先划出“为人”一词,而后发现“民”字只能单独成词了。查表却发现,“民”并不能单独划出,于是考虑进行修正——把“为人”的“人”字分配给“民”字。巧在这下“为”和“人民”正好都能成词,据此便可得出正确的划分“为/人民/服务”。

不过,上述算法归根结底,都是在像人一样从左到右地扫描文字。为了把问题变得更加形式化,充分利用计算机的优势,我们还有一种与人的阅读习惯完全不同的算法思路:把句子作为一个整体来考虑,从全局的角度评价一个句子划分方案的好坏。设计自动分词算法的问题,也就变成了如何评估分词方案优劣的问题。最初所用的办法就是,寻找词数最少的划分。注意,每次都匹配最长的词,得出的划分不见得是词数最少的,错误的贪心很可能会不慎错过一些更优的路。因而,在有的情况下,最少词数法比最大匹配法效果更好。若用最大匹配法来划分,“独立自主和平等互利的原则”将被分成“独立自主/和平/等/互利/的/原则”,一共有 6 个词;但词数更少的方案则是“独立自主/和/平等互利/的/原则”,一共只有 5 个词。

当然,最少词数法也会有踩大便的时候。“为人民办公益”的最大匹配划分和最少词数划分都是“为人/民办/公益”,而正确的划分则是“为/人民/办/公益”。同时,很多句子也有不止一个词数最少的分词方案,最少词数法并不能从中选出一个最佳答案。不过,把之前提到的“不成词字表”装备到最少词数法上,我们就有了一种简明而强大的算法:

对于一种分词方案,里面有多少词,就罚多少分;每出现一个不成词的单字,就加罚一分。最好的分词方案,也就是罚分最少的方案。

这种算法的效果出人意料的好。“他说的确实在理”是一个很困难的测试用例,“的确”和“实在”碰巧也成词,这给自动分词带来了很大的障碍。但是“确”、“实”、“理”通常都不单独成词的,因此很多切分方案都会被扣掉不少分:

他/说/的/确实/在理 (罚分:1+1+1+1+1 = 5 )
      他/说/的确/实/在理 (罚分:1+1+1+2+1 = 6 )
      他/说/的确/实在/理 (罚分:1+1+1+1+2 = 6 )

正确答案胜出。

需要指出的是,这个算法并不需要枚举所有的划分可能。整个问题可以转化为图论中的最短路径问题,利用动态规划效率则会更高。

算法还有进一步加强的余地。大家或许已经想到了,“字不成词”有一个程度的问题。“民”是一个不成词的语素,它是绝对不会单独成词的。“鸭”一般不单独成词,但在儿歌童谣和科技语体中除外。“见”则是一个可以单独成词的语素,只是平时我们不常说罢了。换句话说,每个字成词都有一定的概率,每个词出现的频率也是不同的。

何不用每个词出现的概率,来衡量分词的优劣?于是我们有了一个更标准、更连续、更自动的改进算法:先统计大量真实语料中各个词出现的频率,然后把每种分词方案中各词的出现概率乘起来作为这种方案的得分。利用动态规划,不难求出得分最高的方案。

以“有意见分歧”为例,让我们看看最大概率法是如何工作的。查表可知,在大量真实语料中,“有”、“有意”、“意见”、“见”、“分歧”的出现概率分别是 0.0181 、 0.0005 、 0.0010 、 0.0002 、 0.0001 ,因此“有/意见/分歧”的得分为 1.8×10-9 ,但“有意/见/分歧”的得分只有 1.0×10-11 ,正确方案完胜。

这里的假设是,用词造句无非是随机选词连在一块儿,是一个简单的一元过程。显然,这个假设理想得有点不合理,必然会有很多问题。考虑下面这句话:

这/事/的确/定/不/下来

但是概率算法却会把这个句子分成:

这/事/的/确定/不/下来

原因是,“的”字的出现概率太高了,它几乎总会从“的确”中挣脱出来。

其实,以上所有的分词算法都还有一个共同的大缺陷:它们虽然已经能很好地处理交集型歧义的问题,却完全无法解决另外一种被称为“组合型歧义”的问题。所谓组合型歧义,就是指同一个字串既可合又可分。比如说,“个人恩怨”中的“个人”就是一个词,“这个人”里的“个人”就必须拆开;“这扇门的把手”中的“把手”就是一个词,“把手抬起来”的“把手”就必须拆开;“学生会宣传部”中的“学生会”就是一个词,“学生会主动完成作业”里的“学生会”就必须拆开。这样的例子非常多,“难过”、“马上”、“将来”、“才能”、“过人”、“研究所”、“原子能”都有此问题。究竟是合还是分,还得取决于它两侧的词语。到目前为止,所有算法对划分方案的评价标准都是基于每个词固有性质的,完全不考虑相邻词语之间的影响;因而一旦涉及到组合型歧义的问题,最大匹配、最少词数、概率最大等所有策略都不能实现具体情况具体分析。

于是,我们不得不跳出一元假设。此时,便有了那个 Google 黑板报上提到的统计语言模型算法。对于任意两个词语 w1 、 w2 ,统计在语料库中词语 w1 后面恰好是 w2 的概率 P(w1, w2) 。这样便会生成一个很大的二维表。再定义一个句子的划分方案的得分为 P(∅, w1) · P(w1, w2) · … · P(wn-1, wn) ,其中 w1, w2, …, wn 依次表示分出的词。我们同样可以利用动态规划求出得分最高的分词方案。这真是一个天才的模型,这个模型一并解决了词类标注、语音识别等各类自然语言处理问题。

至此,中文自动分词算是有了一个漂亮而实用的算法。

但是,随便拿份报纸读读,你就会发现我们之前给出的测试用例都太理想了,简直就是用来喂给计算机的。在中文分词中,还有一个比分词歧义更令人头疼的东西——未登录词。中文没有首字母大写,专名号也被取消了,这叫计算机如何辨认人名地名之类的东西?最近十年来,中文分词领域都在集中攻克这一难关。

在汉语的未定义词中,中国人名的规律是最强的了。根据统计,汉语姓氏大约有 1000 多个,其中“王”、“陈”、“李”、“张”、“刘”五大姓氏的覆盖率高达 32% ,前 400 个姓氏覆盖率高达 99% 。人名的用字也比较集中,“英”、“华”、“玉”、“秀”、“明”、“珍”六个字的覆盖率就有 10.35% ,最常用的 400 字则有 90% 的覆盖率。虽然这些字分布在包括文言虚词在内的各种词类里,但就用字的感情色彩来看,人名多用褒义字和中性字,少有不雅用字,因此规律性还是非常强的。根据这些信息,我们足以计算一个字符串能成为名字的概率,结合预先设置的阈值便能很好地识别出可能的人名。

可是,如何把人名从句子中切出来呢?换句话说,如果句中几个连续字都是姓名常用字,人名究竟应该从哪儿取到哪儿呢?人名以姓氏为左边界,相对容易判定一些。人名的右边界则可以从下文的提示确定出来:人名后面通常会接“先生”、“同志”、“校长”、“主任”、“医生”等身份词,以及“是”、“说”、“报道”、“参加”、“访问”、“表示”等动作词。

但麻烦的情况也是有的。一些高频姓氏本身也是经常单独成词的常用字,例如“于”、“马”、“黄”、“常”、“高”等等。很多反映时代性的名字也是本身就成词的,例如“建国”、“建设”、“国庆”、“跃进”等等。更讨厌的就是那些整个名字本身就是常用词的人了,他们会彻底打乱之前的各种模型。如果分词程序也有智能的话,他一定会把所有叫“高峰”、“汪洋”的人拖出去斩了;要是听说了有人居然敢叫“令计划”,估计直接就崩溃了。

还有那些恰好与上下文组合成词的人名,例如:

费孝通向人大常委会提交书面报告
     邓颖超生前使用过的物品

这就是最考验分词算法的句子了。

相比之下,中国地名的用字就分散得多了。北京有一个地方叫“臭泥坑”,网上搜索“臭泥坑”,第一页全是“臭泥坑地图”、“臭泥坑附近酒店”之类的信息。某年《重庆晨报》刊登停电通知,上面赫然印着“停电范围包括沙坪坝区的犀牛屙屎和犀牛屙屎抽水”,读者纷纷去电投诉印刷错误。记者仔细一查,你猜怎么着,印刷并无错误,重庆真的就有叫“犀牛屙屎”和“犀牛屙屎抽水”的地方。

好在,中国地名数量有限,这是可以枚举的。中国地名委员会编写了《中华人民共和国地名录》,收录了从高原盆地到桥梁电站共 10 万多个地名,这让中国地名的识别便利了很多。

真正有些困难的就是识别机构名了,虽然机构名的后缀比较集中,但左边界的判断就有些难了。更难的就是品牌名了。如今各行各业大打创意战,品牌名可以说是无奇不有,而且经常本身就包含常用词,更是给自动分词添加了不少障碍。

最难识别的未登录词就是缩略语了。“高数”、“抵京”、“女单”、“发改委”、“北医三院”都是比较好认的缩略语了,有些缩略语搞得连人也是丈二和尚摸不着头脑。你能猜到“人影办”是什么机构的简称吗?打死你都想不到,是“人工影响天气办公室”。

汉语中构造缩略语的规律很诡异,目前也没有一个定论。初次听到这个问题,几乎每个人都会做出这样的猜想:缩略语都是选用各个成分中最核心的字,比如“安全检查”缩成“安检”,“人民警察”缩成“民警”等等。不过,反例也是有的,“邮政编码”就被缩成了“邮编”,但“码”无疑是更能概括“编码”一词的。当然,这几个缩略语已经逐渐成词,可以加进词库了;不过新近出现的或者临时构造的缩略语该怎么办,还真是个大问题。

说到新词,网络新词的大量出现才是分词系统真正的敌人。这些新词汇的来源千奇百怪,几乎没有固定的产生机制。要想实现对网络文章的自动分词,目前来看可以说是相当困难的。革命尚未成功,分词算法还有很多进步的余地。

漫话中文自动分词和语义识别(下):句法结构和语义结构

 

这篇文章是漫话中文分词算法的续篇。在这里,我们将紧接着上一篇文章的内容继续探讨下去:如果计算机可以对一句话进行自动分词,它还能进一步整理句子的结构,甚至理解句子的意思吗?这两篇文章的关系十分紧密,因此,我把前一篇文章改名为了《漫话中文自动分词和语义识别(上)》,这篇文章自然就是它的下篇。我已经在很多不同的地方做过与这个话题有关的演讲了,在这里我想把它们写下来,和更多的人一同分享。

什么叫做句法结构呢?让我们来看一些例子。“白天鹅在水中游”,这句话是有歧义的,它可能指的是“白天有一只鹅在水中游”,也可能指的是“有一只白天鹅在水中游”。不同的分词方案,产生了不同的意义。有没有什么句子,它的分词方案是唯一的,但也会产生不同的意思呢?有。比如“门没有锁”,它可能是指的“门没有被锁上”,也有可能是指的“门上根本就没有挂锁”。这个句子虽然只能切分成“门/没有/锁”,但由于“锁”这个词既有可能是动词,也有可能是名词,因而让整句话产生了不同的意思。有没有什么句子,它的分词方案是唯一的,并且每个词的词义也都不再变化,但整个句子仍然有歧义呢?有可能。看看这句话:“咬死了猎人的狗”。这句话有可能指的是“把猎人的狗咬死了”,也有可能指的是“一只咬死了猎人的狗”。这个歧义是怎么产生的呢?仔细体会两种不同的意思后,你会发现,句子中最底层的成分可以以不同的顺序组合起来,歧义由此产生。

在前一篇文章中,我们看到了,利用概率转移的方法,我们可以有效地给一句话分词。事实上,利用相同的模型,我们也能给每一个词标注词性。更好的做法则是,我们直接把同一个词不同词性的用法当作是不同的词,从而把分词和词性标注的工作统一起来。但是,所有这样的工作都是对句子进行从左至右线性的分析,而句子结构实际上比这要复杂多了,它是这些词有顺序有层次地组合在一起的。计算机要想正确地解析一个句子,在分词和标注词性后,接下来该做的就是分析句法结构的层次。

在计算机中,怎样描述一个句子的句法结构呢? 1957 年, Noam Chomsky 出版了《句法结构》一书,把这种语言的层次化结构用形式化的方式清晰地描述了出来,这也就是所谓的“生成语法”模型。这本书是 20 世纪为数不多的几本真正的著作之一,文字非常简练,思路非常明晰,震撼了包括语言学、计算机理论在内的多个领域。记得 Quora 上曾经有人问 Who are the best minds of the world today ,投出来的答案就是 Noam Chomsky 。

随便取一句很长很复杂的话,比如“汽车被开车的师傅修好了”,我们总能自顶向下地一层层分析出它的结构。这个句子最顶层的结构就是“汽车修好了”。汽车怎么修好了呢?汽车被师傅修好了。汽车被什么样的师傅修好了呢?哦,汽车被开车的师傅修好了。当然,我们还可以无限地扩展下去,继续把句子中的每一个最底层的成分替换成更详细更复杂的描述,就好像小学语文中的扩句练习那样。这就是生成语法的核心思想。

熟悉编译原理的朋友们可能知道“上下文无关文法”。其实,上面提到的扩展规则本质上就是一种上下文无关文法。例如,一个句子可以是“什么怎么样”的形式,我们就把这条规则记作

句子 → 名词性短语+动词性短语

其中,“名词性短语”指的是一个具有名词功能的成分,它有可能就是一个名词,也有可能还有它自己的内部结构。例如,它有可能是一个形容词性短语加上“的”再加上另一个名词性短语构成的,比如“便宜的汽车”;它还有可能是由“动词性短语+的+名词性短语”构成的,比如“抛锚了的汽车”;它甚至可能是由“名词性短语+的+名词性短语”构成的,比如“老师的汽车”。我们把名词性短语的生成规则也都记下来:

名词性短语 → 名词
      名词性短语 → 形容词性短语+的+名词性短语
      名词性短语 → 动词性短语+的+名词性短语
      名词性短语 → 名词性短语+的+名词性短语
      ??

类似地,动词性短语也有诸多具体的形式:

动词性短语 → 动词
      动词性短语 → 动词性短语+了
      动词性短语 → 介词短语+动词性短语
      ??

上面我们涉及到了介词短语,它也有自己的生成规则:

介词短语 → 介词+名词性短语
      ??

我们构造句子的任务,也就是从“句子”这个初始结点出发,不断调用规则,产生越来越复杂的句型框架,然后从词库中选择相应词性的单词,填进这个框架里:

                     

而分析句法结构的任务,则是已知一个句子从左到右各词的词性,要反过来求出一棵满足要求的“句法结构树”。这可以用 Earley parser 来实现。

这样看来,句法结构的问题似乎就已经完美的解决了。其实,我们还差得很远。生成语法有两个大问题。首先,句法结构正确的句子不见得都是好句子。 Chomsky 本人给出了一个经典的例子: Colorless green ideas sleep furiously 。形容词加形容词加名词加动词加副词,这是一个完全符合句法要求的序列,但随便拼凑会闹出很多笑话——什么叫做“无色的绿色的想法在狂暴地睡觉”?顺便插播个广告,如果你还挺喜欢这句话的意境的,欢迎去我以前做的IdeaGenerator 玩玩。不过,如果我们不涉及句子的生成,只关心句子的结构分析,这个缺陷对我们来说影响似乎并不大。生成语法的第二个问题就比较麻烦了:从同一个词性序列出发,可能会构建出不同的句法结构树。比较下面两个例子:

老师 被 迟到 的 学生 逗乐 了
      电话 被 窃听 的 房间 找到 了

它们都是“名词+介词+动词+的+名词+动词+了”,但它们的结构并不一样,前者是老师被逗乐了,“迟到”是修饰“学生”的,后者是房间找到了,“电话被窃听”是一起来修饰房间的。但是,纯粹运用前面的模型,我们无法区分出哪句话应该是哪个句法结构树。如何强化句法分析的模型和算法,让计算机构建出一棵正确的句法树,这成了一个大问题。

让我们来看一个更简单的例子吧。同样是“动词+形容词+名词”,我们有两种构建句法结构树的方案:

未经过汉语语法训练的朋友可能会问,“点亮蜡烛”和“踢新皮球”的句法结构真的不同吗?我们能证明,这里面真的存在不同。我们造一个句子“踢破皮球”,你会发现对于这个句子来说,两种句法结构都是成立的,于是出现了歧义:把皮球踢破了(结构和“点亮蜡烛”一致),或者是,踢一个破的皮球(结构和“踢新皮球”一致)。

但为什么“点亮蜡烛”只有一种理解方式呢?这是因为我们通常不会把“亮”字直接放在名词前做定语,我们一般不说“一根亮蜡烛”、“一颗亮星星”等等。为什么“踢新皮球”也只有一种理解方式呢?这是因为我们通常不会把“新”直接放在动词后面作补语,不会说“皮球踢新了”,“衣服洗新了”等等。但是“破”既能作定语又能作补语,于是“踢破皮球”就产生了两种不同的意思。如果我们把每个形容词能否作定语,能否作补语都记下来,然后在生成规则中添加限制条件,不就能完美解决这个问题了吗?

基于规则的句法分析器就是这么做的。汉语语言学家们已经列出了所有词的各种特征:

亮:词性 = 形容词,能作补语 = True ,能作定语 = False ??
      新:词性 = 形容词,能作补语 = False ,能作定语 = True ??
      ??

当然,每个动词也有一大堆属性:

点:词性 = 动词,能带宾语 = True ,能带补语 = True ??
      踢:词性 = 动词,能带宾语 = True ,能带补语 = True ??
      污染:词性 = 动词,能带宾语 = True ,能带补语 = False ??
      排队:词性 = 动词,能带宾语 = False ,能带补语 = False ??
      ??

名词也不例外:

蜡烛:词性 = 名词,能作主语 = True ,能作宾语 = True ,能受数量词修饰 = True ??
      皮球:词性 = 名词,能作主语 = True ,能作宾语 = True ,能受数量词修饰 = True ??
      ??

有人估计会觉得奇怪了:“能作主语”也是一个属性,莫非有些名词不能做主语?哈哈,这样的名词不但有,而且还真不少:剧毒、看头、厉害、正轨、存亡??这些词都不放在动词前面。难道有些名词不能做宾语吗?这样的词也有不少:享年、芳龄、心术、浑身、家丑??这些词都不放在动词后面。这样说来,存在不受数量词修饰的词也就不奇怪了,事实上上面这些怪异的名词前面基本上都不能加数量词。

另外一个至关重要的就是,这些性质可以“向上传递”。比方说,我们规定,套用规则

名词性短语 → 形容词性短语+名词性短语

后,整个名词性短语能否作主语、能否作宾语、能否受数量词修饰,这将取决于它的第二个构成成分。通俗地讲就是,如果“皮球”能够作主语,那么“新皮球”也能够作主语。有了“词语知识库”,又确保了这些知识能够在更高层次得到保留,我们就能给语法生成规则添加限制条件了。例如,我们可以规定,套用规则

动词性短语 → 动词性短语+名词性短语

的前提条件就是,那个动词性短语的“能带宾语”属性为 True ,并且那个名词性短语“能作宾语”的属性为 True 。另外,我们规定

动词性短语 → 动词性短语+形容词性短语

必须满足动词性短语的“能带补语”属性为 True ,并且形容词性短语“能作补语”属性为 True 。这样便阻止了“踢新皮球”中的“踢”和“新”先结合起来,因为“新”不能作补语。

最后我们规定,套用规则

名词性短语 → 形容词性短语+名词性短语

时,形容词性短语必须要能作定语。这就避免了“点亮蜡烛”中的“亮”和“蜡烛”先组合起来,因为“亮”通常不作定语。这样,我们便解决了“动词+形容词+名词”的结构分析问题。

当然,这只是一个很简单的例子。在这里的问题 6 、 7 、 8 中你可以看到,一条语法生成规则往往有很多限制条件,这些限制条件不光是简单的“功能相符”和“前后一致”,有些复杂的限制条件甚至需要用 IF … THEN … 的方式来描述。你可以在这里看到,汉语中词与词之间还有各种怪异的区别特征,并且哪个词拥有哪些性质纯粹是知识库的问题,完全没有规律可循。一个实用的句法结构分析系统,往往拥有上百种属性标签。北京大学计算语言所编写了《现代汉语语法信息词典》,它里面包含了 579 种属性。我们的理想目标就是,找到汉语中每一种可能会影响句法结构的因素,并据此为词库里的每一个词打上标签;再列出汉语语法中的每一条生成规则,找到每一条生成规则的应用条件,以及应用这条规则之后,整个成分将会以怎样的方式继承哪些子成分的哪些属性,又会在什么样的情况下产生哪些新的属性。按照生成语言学的观点,计算机就应该能正确解析所有的汉语句子了。

那么,这样一来,计算机是否就已经能从句子中获取到理解语义需要的所有信息了呢?答案是否定的。还有这么一些句子,它从分词到词义到结构都没有两可的情况,但整个句子仍然有歧义。考虑这句话“鸡不吃了”,它有两种意思:鸡不吃东西了,或者我们不吃鸡了。但是,这种歧义并不是由分词或者词义或者结构导致的,两种意思所对应的语法结构完全相同,都是“鸡”加上“不吃了”。但为什么歧义仍然产生了呢?这是因为,在句法结构内部,还有更深层次的语义结构,两者并不相同。

汉语就是这么奇怪,位于主语位置上的事物既有可能是动作的发出者,也有可能是动作的承受者。“我吃完了”可以说,“苹果吃完了”也能讲。然而,“鸡”这个东西既能吃,也能被吃,歧义由此产生。

位于宾语位置上的事物也不一定就是动作的承受者,“来客人了”、“住了一个人”都是属于宾语反而是动作发出者的情况。记得某次数理逻辑课上老师感叹,汉语的谓词非常不规范,明明是太阳在晒我,为什么要说成是“我晒太阳”呢?事实上,汉语的动宾搭配范围极其广泛,还有很多更怪异的例子:“写字”是我们真正在写的东西,“写书”是写的结果,“写毛笔”是写的工具,“写楷体”是写的方式,“写地上”是写的场所,“写一只狗”,等等,什么叫做“写一只狗”啊?我们能说“写一只狗”吗?当然可以,这是写的内容嘛,“同学们这周作文写什么啊”,“我写一只狗”。大家可以想像,学中文的老外看了这个会是什么表情。虽然通过句法分析,我们能够判断出句子中的每样东西都和哪个动词相关联,但从语义层面上看这个关联是什么,我们还需要新的模型。

汉语语言学家把事物与动词的语义关系分为了 17 种,叫做 17 种“语义角色”,它们是施事、感事、当事、动力、受事、结果、系事、工具、材料、方式、内容、与事、对象、场所、目标、起点、时间。你可以看到,语义角色的划分非常详细。同样是动作的发出者,施事指的是真正意义上的发出动作,比如“他吃饭”中的“他”;感事则是指某种感知活动的经验者,比如“他知道这件事了”中的“他”;当事则是指性质状态的主体,比如“他病了”中的“他”;动力则是自然力量的发出者,比如“洪水淹没了村庄”中的“洪水”。语义角色的具体划分以及 17 这个数目是有争议的,不过不管怎样,这个模型本身能够非常贴切地回答“什么是语义”这个问题。

汉语有一种“投射理论”,即一个句子的结构是由这个句子中的谓语投射出来的。给定一个动词后,这个动词能够带多少个语义角色,这几个语义角色都是什么,基本上都已经确定了。因而,完整的句子所应有的结构实际上也就已经确定了。比如,说到“休息”这个动词,你就会觉得它缺少一个施事,而且也不缺别的了。我们只会说“老王休息”,不会说“老王休息手”或者“老王休息沙发”。因而我们认为,“休息”只有一个“论元”。它的“论元结构”是:

休息 <施事>

因此,一旦在句子中看到“休息”这个词,我们就需要在句内或者句外寻找“休息”所需要的施事。这个过程有一个很帅的名字,叫做“配价”。“休息”就是一个典型的“一价动词”。我们平时接触的比较多的则是二价动词。不过,它们具体的论元有可能不一样:

吃 <施事,受事>
      去 <施事,目标>
      淹没 <动力,受事>

三价动词也是有的,例如

送 <施事,受事,与事>

甚至还有零价动词,例如

下雨 <Ф>

下面我们要教计算机做的,就是怎样给动词配价。之前,我们已经给出了解析句法结构的方法,这样计算机便能判断出每个动词究竟在和哪些词发生关系。语义分析的实质,就是确定出它们具体是什么关系。因此,语义识别的问题,也就转化为了“语义角色标注”的问题。然而,语义角色出现的位置并不固定,施事也能出现在动词后面,受事也能出现在动词前面,怎样让计算机识别语义角色呢?在回答这个问题之前,我们不妨问问自己:我们是怎么知道,“我吃完了”中的“我”是“吃”的施事,“苹果吃完了”中的“苹果”是“吃”的受事的呢?大家肯定会说,废话,“我”当然只能是“吃”的施事,因为我显然不会“被吃”;“苹果”当然只能是“吃”的受事,因为苹果显然不能发出“吃”动作。也就是说,“吃”的两个论元都有语义类的要求。我们把“吃”的论元结构写得更详细一些:

吃 <施事[语义类:人|动物],受事[语义类:食物|药物]>

而“淹没”一词的论元结构则可以补充为:

淹没 <动力[语义类:自然事物],受事[语义类:建筑物|空间]>

所以,为了完成计算机自动标注语义角色的任务,我们需要人肉建立两个庞大的数据库:语义类词典和论元结构词典。这样的人肉工程早就已经做过了。北京语言大学 1990 年 5 月启动的“九〇?五语义工程”就是人工构建的一棵规模相当大的语义树。它把词语分成了事物、运动、时空、属性四大类,其中事物类分为事类和物类,物类又分为具体物和抽象物,具体物则再分为生物和非生物,生物之下则分了人类、动物、植物、微生物、生物构件五类,非生物之下则分了天然物、人工物、遗弃物、几何图形和非生物构件五类,其中人工物之下又包括设施物、运载物、器具物、原材料、耗散物、信息物、钱财七类。整棵语义树有 414 个结点,其中叶子结点 309 个,深度最大的地方达到了 9 层。论元结构方面则有清华大学和人民大学共同完成的《现代汉语述语动词机器词典》,词典中包括了各种动词的拼音、释义、分类、论元数、论元的语义角色、论元的语义限制等语法和语义信息。

说到语义工程,不得不提到董振东先生的知网。这是一个综合了语义分类和语义关系的知识库,不但通过语义树反映了词与词的共性,还通过语义关系反映了每个词的个性。它不但能告诉你“医生”和“病人”都是人,还告诉了你“医生”可以对“病人”发出一个“医治”的动作。知网的理念和 WordNet 工程很相似,后者是 Princeton 在 1985 年就已经开始构建的英文单词语义关系词典,背后也是一个语义关系网的概念,词与词的关系涉及同义词、反义词、上下位词、整体与部分、子集与超集、材料与成品等等。如果你装了 Mathematica,你可以通过 WordData 函数获取到 WordNet 的数据。至于前面说的那几个中文知识库嘛,别问我,我也不知道上哪儿取去。

看到这里,想必大家会欢呼,啊,这下子,在中文信息处理领域,从语法到语义都已经漂亮的解决了吧。其实并没有。上面的论元语义角色的模型有很多问题。其中一个很容易想到的就是隐喻的问题,比如“信息淹没了我”、“悲伤淹没了我”。一旦出现动词的新用法,我们只能更新论元结构:

淹没 <动力[语义类:自然事物|抽象事物],受事[语义类:建筑物|空间|人类]>

但更麻烦的则是下面这些违背语义规则的情况。一个是否定句,比如“张三不可能吃思想”。一个是疑问句,比如“张三怎么可能吃思想”。更麻烦的就是超常现象。随便在新闻网站上一搜,你就会发现各种不符合语义规则的情形。我搜了一个“吃金属”,立即看到某新闻标题《法国一位老人以吃金属为生》。要想解决这些问题,需要给配价模型打上不少补丁。

然而,配价模型也仅仅解决了动词的语义问题。其他词呢?好在,我们也可以为名词发展一套类似的配价理论。我们通常认为“教师”是一个零价名词,而“老师”则是一个一价名词,因为说到“老师”时,我们通常会说“谁的老师”。“态度”则是一个二价的名词,因为我们通常要说“谁对谁的态度”才算完整。事实上,形容词也有配价,“优秀”就是一个一价形容词,“友好”则是一个二价形容词,原因也是类似的。配价理论还有很多更复杂的内容,这里我们就不再详说了。

但还有很多配价理论完全无法解决的问题。比如,语义有指向的问题。“砍光了”、“砍累了”、“砍钝了”、“砍快了”,都是动词后面跟形容词作补语,但实际意义各不相同。“砍光了”指的是“树砍光了”,“砍累了”指的是“人砍累了”,“砍钝了”指的是“斧子砍钝了”,“砍快了”指的是“砍砍快了”。看来,一个动词的每个论元不但有语义类的限制,还有“评价方式”的限制。

两个动词连用,也有语义关系的问题。“抓住不放”中,“抓住”和“不放”这两个动作构成一种反复的关系,抓住就等于不放。“说起来气人”中,“说起来”和“气人”这两个动作构成了一种条件关系,即每次发生了“说起来”这个事件后,都会产生“气人”这个结果。大家或许又会说,这两种情况真的有区别吗?是的,而且我能证明这一点。让我们造一个句子“留着没用”,你会发现它出现了歧义:既可以像“抓住不放”一样理解为反复关系,一直把它留着一直没有使用;又可以像“说起来气人”一样理解为条件关系,留着的话是不会有用的。因此,动词与动词连用确实会产生不同的语义关系,这需要另一套模型来处理。

虚词的语义更麻烦。别以为“了”就是表示完成,“这本书看了三天”表示这本书看完了,“这本书看了三天了”反而表示这本书没看完。“了”到底有多少个义项,现在也没有一个定论。副词也算虚词,副词的语义同样捉摸不定。比较“张三和李四结婚了”与“张三和李四都结婚了”,你会发现描述“都”字的语义没那么简单。

不过,在实际的产品应用中,前面所说的这些问题都不大。这篇文章中讲到的基本上都是基于规则的语言学处理方法。目前更实用的,则是对大规模真实语料的概率统计分析与机器学习算法,这条路子可以无视很多具体的语言学问题,并且效果也相当理想。最大熵模型和条件随机场都是目前非常常用的自然语言处理手段,感兴趣的朋友可以深入研究一下。但是,这些方法也有它们自己的缺点,就是它们的不可预测性。不管哪条路,似乎都离目标还有很远的一段距离。期待在未来的某一日,自然语言处理领域会迎来一套全新的语言模型,一举解决前面提到的所有难题。

时间: 2024-08-11 05:54:47

漫话中文分词的相关文章

PHP中文分词扩展 SCWS

1.scws简介 SCWS 是 Simple Chinese Word Segmentation 的首字母缩写(即:简易中文分词系统). 这是一套基于词频词典的机械式中文分词引擎,它能将一整段的中文文本基本正确地切分成词. 词是中文的最小语素单位,但在书写时并不像英语会在词之间用空格分开, 所以如何准确并快速分词一直是中文分词的攻关难点. SCWS 采用纯 C 语言开发,不依赖任何外部库函数,可直接使用动态链接库嵌入应用程序, 支持的中文编码包括 GBK.UTF-8 等.此外还提供了 PHP 扩

Elasticsearch安装中文分词插件ik

Elasticsearch默认提供的分词器,会把每个汉字分开,而不是我们想要的根据关键词来分词.例如: curl -XPOST "http://localhost:9200/userinfo/_analyze?analyzer=standard&pretty=true&text=我是中国人" 我们会得到这样的结果: { tokens: [ { token: text start_offset: 2 end_offset: 6 type: <ALPHANUM>

中文分词实践(基于R语言)

背景:分析用户在世界杯期间讨论最多的话题. 思路:把用户关于世界杯的帖子拉下来,然后做中文分词+词频统计,最后将统计结果简单做个标签云,效果如下: 后续:中文分词是中文信息处理的基础,分词之后,其实还有特别多有趣的文本挖掘工作可以做,也是个知识发现的过程,以后有机会再学习下. ================================================== * 中文分词常用实现: 单机:R语言+Rwordseg分词包 (建议数据量<1G) 分布式:Hadoop+Smallse

中文分词之结巴分词~~~附使用场景+demo

常用技能(更新ing):http://www.cnblogs.com/dunitian/p/4822808.html#skill 技能总纲(更新ing):http://www.cnblogs.com/dunitian/p/5493793.html 在线演示:http://cppjieba-webdemo.herokuapp.com 完整demo:https://github.com/dunitian/TempCode/tree/master/2016-09-05 先说下注意点,结巴分词他没有对分

php+中文分词scws+sphinx+mysql打造千万级数据全文搜索

Sphinx是由俄罗斯人Andrew Aksyonoff开发的一个全文检索引擎.意图为其他应用提供高速.低空间占用.高结果 相关度的全文搜索功能.Sphinx可以非常容易的与SQL数据库和脚本语言集成.当前系统内置MySQL和PostgreSQL 数据库数据源的支持,也支持从标准输入读取特定格式 的XML数据.Sphinx创建索引的速度为:创建100万条记录的索引只需3-4分钟,创建1000万条记录的索引可以在50分钟内完成,而只包含最新10万条记录的增量索引,重建一次只需几十秒.Sphinx的

python 读写txt文件并用jieba库进行中文分词

python用来批量处理一些数据的第一步吧. 对于我这样的的萌新.这是第一步. #encoding=utf-8 file='test.txt' fn=open(file,"r") print fn.read() fn.close() 在控制台输出txt文档的内容,注意中文会在这里乱码.因为和脚本文件放在同一个地方,我就没写路径了. 还有一些别的操作. 这是文件open()函数的打开mode,在第二个参数中设置.特别需要注意一下.具体还有一些别的细节操作. http://www.jb51

【Lucene】Apache Lucene全文检索引擎架构之中文分词和高亮显示

前面总结的都是使用Lucene的标准分词器,这是针对英文的,但是中文的话就不顶用了,因为中文的语汇与英文是不同的,所以一般我们开发的时候,有中文的话肯定要使用中文分词了,这一篇博文主要介绍一下如何使用smartcn中文分词器以及对结果的高亮显示. 1. 中文分词 使用中文分词的话,首先到添加中文分词的jar包. <!-- lucene中文分词器 --> <dependency> <groupId>org.apache.lucene</groupId> <

在Hadoop上运行基于RMM中文分词算法的MapReduce程序

原文:http://xiaoxia.org/2011/12/18/map-reduce-program-of-rmm-word-count-on-hadoop/ 在Hadoop上运行基于RMM中文分词算法的MapReduce程序 23条回复 我知道这个文章标题很“学术”化,很俗,让人看起来是一篇很牛B或者很装逼的论文!其实不然,只是一份普通的实验报告,同时本文也不对RMM中文分词算法进行研究.这个实验报告是我做高性能计算课程的实验里提交的.所以,下面的内容是从我的实验报告里摘录出来的,当作是我学

简单中文分词系统的实现

中文分词系统工程报告 一.研究背景 随着互联网的快速发展,信息也呈了爆炸式的增长趋势.在海量的信息中,我们如何快速抽取出有效信息成为了必须要解决的问题.由于信息处理的重复性,而计算机又善于处理机械的.重复的.有规律可循的工作,因此自然就想到了利用计算机来帮助人们进行处理.在用计算机进行自然语言处理时,主要使用的还是基于统计的方法,并且实际的使用中取得了不错的效果. 因为中文句子的特点——没有分隔符来分离句子中的词,所以在进行中文处理的时候,首先要做的就是如何对中文语句进行分词.这也是本次工程所要