[先说一下, 上次的语言识别程序的思路来自 Python Cookbook, 我只是略作修改, 并没有什么太大的贡献, 这个系列可能包含三到四篇文章. 底下我可能会用朴素贝页斯分类器再写一个然后比较两者效果]
以前我在翻译怎样写一个拼写检查器中, 就提到了(概率)语言模型这个东西. 什么是语言模型呢, 简单的说, 就是这个语言当中, 每个词出现的概率分布是有一定规律的, 与其他因素无关的. 如果我们要写一个汉语到英文的翻译器, 那么, 理论上说, 我们翻译器输出来的结果当中每个单词出现的概率, 应该和英文当中每个词出现的概率一样. 试想一下, the 这个单词在英文中常常出现, 而如果我们的翻译器对于任意汉语的翻译结果中, 故意调低或者错误设置 the 出现的概率, 造成翻译出来的结果几乎不出现 the, 或者出现的概率出奇的奇怪, 那么, 这段翻译出来的话, 它怎么看也不会像英语. 同样的道理, 一个拼写检查器可以把任意拼错的单词纠正过来, 在纠正过程中必须照顾到语言模型. 如果 teh 可以被改正为 the 和 tek, 那么我们应该优先考虑 the 才对, 因为 the 被使用的概率比 tek 大. (统计语言模型整体是很大的一块, 大家可以去读 Google 黑板报数学之美系列得到一个大致的感觉. 我这里只用到语言模型, 用不到条件概率)
基于这个假设, 我们自然的得到一个主意: 好呀, 假如两个文本的语言模型类似, 我们就认为他们是同种语言写成的. 对的, 怎么衡量这个类似呢, 我们可以用数学的方法: 统计任何两个语言模型之间的”距离”, 然后选取最小的. 这个地方距离随便怎么定义, 可以用向量夹角, 可以用欧式距离. 但是, 现实的问题不是这么简单. 首先, 如果每个词都对应一个词频的话, 得到的向量是高维的. 除非有一个包含各种语言单词的全集, 否则很难说这个向量一共要有多少个维度. 而且高维的随机向量还往往以很大的概率正交. 为了控制维度灾难, 一个简单的方法是使用每一个字节作为一个词统计. 这个模型虽然看上去很没道理, 而且还很”面向机器”, 但是考虑到计算机处理语言的时候本来也就是根据字节来处理, 这样做一下也未尝不可.
我并没有亲自实践比较字节频率然后计算向量距离的方法, 不过我可以想像, 这样的方法在UTF-8字符集上是有很好表现的. 有人可能会担心, 加入某个汉字编码成了两个字节, 这两个字节正好分别等于西文字母的编码的话, 汉字就可以在计算机中等价的写成一串字母了, 这样, 就很难保证一段汉字是不是和一段希腊文正好有同样的字节分布了, 因为我们可以作弊一下, 搞出一段汉字, 正好和希腊文对应分布一样. 但是, 巧妙之处在于UTF-8 字符集本身通过若干前缀区分了不同的变长编码, 不同的编码区段没有任何交集. 反过来说就是, 从UTF-8 编码的字节序列中任意取一个字节出来, 一定能够区分这个字节是某个变长编码的一部分. 任何一个多字节符号编出来的编码的一部分, 绝对不可能正好是其他单字节符号的编码. 这样, 单字节多字节变成字节编码后各自为政, 映射到的字节码的概率分布不会出现“作弊”现象. 用严格的数学语言来说就是, 一个字符对应的字节在叠加到向量中的时候, 绝对不会叠加到属于另一个字符的所有字节上, 也就是说, 他们总有独立分布的部分存在. 这个是字节模型能正确反映语言模型的一个必要要求.
[To be continued…]