首先说明中文输入法,由于在计算机的输入设备中,输入使用的键盘使用的是ascii码,只能输入英文字符串。中文输入法的作用是将用户输入的英文字符串转换为有意义的中文输入组合,输入计算机。常用的是拼音输入法,这种输入法是将汉字的拼音与英文字母直接映射起来,由于这是一一映射的关系,所以理解起来最直观,也应用的最广泛。其他的还有如五笔输入法,是将汉字的偏旁部首映射到英文字母上去,每个英文字母对应于若干个偏旁部首,在输入汉字时,需要先将汉字拆分开,然后找到相应的英文字母输入,得到相对应的汉字。五笔输入法的优点是:冲突率低,当输入相应的英文字串时,往往得到的是唯一的中文字符,不用再去选择。而拼音输入法中,由于同音字较多,当输入一串英文字串时,得到的是若干个中文字符,需要再进行选择。而五笔输入法的缺点是:在输入时,需要将汉字拆分,然后找到相应的映射英文字母再进行输入,需要记录一个映射表,即所谓的五笔字型码。拼音输入法与五笔输入法相比较的话,其冲突率高,但是理解起来直观,更符合人们日常生活的习惯,所以被更多的人所使用。本文中讲的就是拼音输入法。
考虑一个中文输入法的实现:
目标:输入英文字母序列,返回相应可能的输入字或者词的组合。
从最简单的开始
需求:输入一个英文字串,返回其精确匹配的单字。
所需要准备的知识:单字所对应的输入英文字串词典,一种根据输入字符串找到相应单字的算法。
例如:输入“shu”,返回其所对应的所有精确匹配的单字,“树,数,书,熟”等。
实现说明:
对于所有汉字,建立其一个对应表。这个知识需要人工整理。
数据整理为如下格式:
一 yi
…
书 shu
数 shu
…
开 kai
数据结构选择:
(1)Hash.由于是一一映射的关系,可以用Hash,以汉字为关键字,以英文字串为值。在输入字符串后,在hash表中查找所有值等于该字符串的单元的关键字,搜索复杂度为O(n).而且每次输入一次时,要搜索一次。如果字符串的长度为k,那么找到目标串的复杂度为O(k*n).复杂度较高。
(2)MultiSet. C++中的STL中的MultiSet允许存储重复的值。以英文字串为关键字,以汉字为值。在输入字符串后,就得到了其对应的汉字集合。复杂度为O(1).每输入一次时,由于multiset用的是红黑树实现的,是平衡树,所以搜索时的复杂度为O(logk),找到目标集合的复杂度为O(1*log k) = O(k*log k),只与长度有关系。
(3)Trie树.其搜索的复杂度和串的长度成正比,复杂度为O(k*k)。
显然第二种方法效率要高得多。
稍微复杂一点的情况
上面一个缺点是必须得精确匹配。就是说,在用户输入“shu”时,在输入前两个字母时,由于在词典中没有匹配上的串,程序没有任何输出。
下面就为其加上模糊匹配的功能。
使用前缀树或者双Trie树的数据结构。其可以查询所有以当前输入为前缀的候选词。搜索代价为O(k),只与输入串长度有关。
加入频率信息
在给出的候选词中,其排序是随机的,与加入词典的先后顺序有关或者是字典序。根据统计将高频词放在前面,可以减少用户继续往下翻的次数,大大提高人们输入的效率。通过语料统计,获取单字和词的频率,对于候选串,按照频率从高到低排列。
从单字到多词
使用语言模型(Language Model),使用二元或者三元的语言模型(2-gram或者3-gram)。将成词概率高的排在前面。
动态更新词典
发现的新词,用户频繁输入的词,都可以加入词典。可以把词典分为两部分,一部分是全局词典,是有基础词典以及广泛使用的新词(定期更新)构成的。一个是用户词典,保存的是当前用户的使用习惯和经常使用的组合。加权组合后重新排序。
从单字精确匹配到单字模糊匹配:
首先,根据已经输入的内容,去匹配所有可能的字符串。比较适合的结构是前缀树和Trie树(前缀树的一种)。找出当前前缀下所对应节点的所有子节点对应的候选单字。
加入字频信息:
当输入一个串时,其对应的汉字单字可能会有很多,在提供给用户可能的候选单字时,可以对候选单字按照字频进行排序,将高频字排在前面。
数据重新整理为
一 yi 3000
…
书 shu 500
数 shu 600
…
开 kai 1200
原数据结构需要加入词频这个域。对查到的结果,按照词频排序。
构建的这个词典,应该满足如下需求:方便动态更新,词频的数据应该可以修改。
由单字向单词、词组进发:
之前都是匹配单字。下面将其改得更加复杂,更加实用一些:支持输入单词及词组。
首先,是精确匹配。
例如:输入“shuju”,给返回匹配的词组“数据,书局”等。这里要引入一个语言模型的概念。一般拼音输入法中使用的是二元的甚至三元的语言模型。就是对语料中两个连续的字或者三个连续的字频率做统计。
二元语言模型数据统计示例如下:
一起 1000
……
数据 1200
书局 500
三元语言模型数据会比二元语言数据量大上一个数量级。实际上,在语言模型中,当语言模型的维数增加时,数据量都成级别的增长,虽然维数越大,越精确,当数据量会剧增,而且数据会变得很sparse,在使用时应该根据实际的应用需求权衡选择。
计算组合概率:
当使用二元模型时,对于二字词,可以使用与单字相同的处理方法来处理,对于二字以上的词,例如三字词,四字词等,就需要用组合概率来处理了。
例如P(“一起玩”)=P(“一起”)*P(“起玩”)。
下面进一步升级为模糊匹配,并且给出其一般的解决方案,作为最终的版本
例如,输入“shjk”,列出“数据库,数据卡,手机卡”等候选词。
首先是,获得一个模糊匹配划分方案,“shjk”应该被划分为“sh”,“j”,“k”,有的输入可能有多个划分方案,例如“xian”,可能被划分为“xi”,“an”,也可能被划分为“xian”。对于有多个划分方案的,每个方案都应该考虑。继续考察“shjk”。
对于划分“sh”,“j”,“k”,找出“sh”对应的候选字,“j”对应的候选字,“k”对应的候选字。对于所有可能的组合,计算出其组合频率,然后按组合频率从大到小的顺序列出来供用户选择。
知识获取:
语言模型的数据,需要通过跑语料来获得。语料越大,质量越高,获得的数据越可靠,输入法的效果表现越好。
一元数据获取方法:汉字字库。常用汉字约3500个。汉字库约8万个。
二元数据获取方法:中文语料。对语料进行分句处理。对于句子中相邻的两个字进行统计、计数,获得的结果作为二元数据。
补:对于手机汉字输入法的思考。
在原输入法的基础上,由于手机中,一个输入(为数字键)对应多个拼音字母,需要对于输入的所有按键可能拼音组合进行分析。例如,按下“2”和“3”键,2对应的拼音字母为“abc”,3对应的拼音字母为“def”,那么要穷举3*3=9种组合的情况,然后去前缀树词典中去查找合法的输入。
涉及到的相关算法:
1. 前缀树算法实现。用于查词典算法。推荐实现双Trie树算法。实现一个简单的玩玩,用Hash或者Multiset就可以了。
2. 穷举可能的组合方案。用于“shuju”这样精确匹配组合方案。
3. 穷举可能的划分方案。用于“shjk”这样的模糊匹配可能划分方案的穷举。
4. 组合概率的计算。
5. 语言模型数据统计。
奇思妙想:
使用输入法来辅助中文分词。在中文句子输入时,一般都是按照词或者词组输入,这个过程中其实就提供了一个分词的信息。如果在用户输入时,能够把用户输入时的输入信息保留下来,那么对于分词是非常有用的。例如,用户输入下面一个句子:“中国政府和人民愿与国际社会携手努力”,用户是这么输入的“中国政府 和 人民 愿 与 国际社会 携手努力”,其中的空格是用户的输入停顿。那么这个句子就是一个天然的分好了词的句子。这种方法需要满足下面两个要求:1,在用户输入时,能够记录用户的输入信息:在哪个地方停顿等。2,记录信息的同时,不能对用户产生影响,应该还是原来一样的输出结果,但是信息已经存储在数据中了,而对用户是不可见的,在分词时又能把这个信息提取出来,辅助分词。
输入法对中文分词的影响:从上面可以看出,合理利用输入法的信息能够有效地提高分词的效果和效率。另外,中文分词中影响分词效果非常重要的一个是:新词词表。通过输入法的运营,可以有效地收集用户的输入,发现新词。
输入法与搜索引擎,信息检索的关系:在一些搜索引擎中,输入拼音也可以找到相应的词条,说明搜索引擎在query suggestion时,已经整合了输入法的部分技术。输入法技术对于搜索引擎也是非常重要的一部分。
(To be continue)
本人原创,转载请注明出处!谢谢。