基于贝叶斯公式的拼音输入法二元模型实现
和英語的直接輸入不同,漢語輸入法是通過拼音轉(zhuǎn)譯輸入,而由于不同的拼音可以對(duì)應(yīng)同一個(gè)字,而不同的字也可能存在多個(gè)拼音,是一個(gè)多對(duì)多的關(guān)系,因此在獲得拼音的時(shí)候,需要能夠準(zhǔn)確地將其轉(zhuǎn)換為正確的漢字,這就是拼音輸入法的作用。本文介紹了一種基于貝葉斯公式的全拼拼音輸入法實(shí)現(xiàn),全拼也就是輸入完整的拼音,不考慮縮寫等情況。
以下是一段拼音:
huan ying guan zhu wo de bo ke
對(duì)于我們?nèi)藖碚f,可以很容易的知道每個(gè)拼音對(duì)應(yīng)的是哪個(gè)字:
歡迎關(guān)注我的博客
但是對(duì)于計(jì)算機(jī),拼音所對(duì)應(yīng)的每個(gè)漢字都是等價(jià)的,比如huan可以是“歡”,也可以是“換”,那么如果讓計(jì)算機(jī)知道在這個(gè)句子里huan是“歡”?參考一下人將拼音轉(zhuǎn)化為漢字的過程,可以發(fā)現(xiàn)在判斷某個(gè)拼音的時(shí)候,我們并不是僅僅根據(jù)那一個(gè)拼音去判斷,而是將其放在整個(gè)句子的上下文環(huán)境里去判斷,也就是說在給定拼音句子的情況下,找到最大概率的漢字句子。翻譯成數(shù)學(xué)語言就是,令X為漢字句子,Y為拼音句子,求
根據(jù)貝葉斯公式
其中
為常量,因?yàn)槠匆粢呀?jīng)固定,
????使用識(shí)別信度代替,
考慮到隨著n的增加,該計(jì)算會(huì)越來越復(fù)雜,并且會(huì)增加數(shù)據(jù)稀疏性,因此使用二元模型,即每個(gè)字的概率只和它前一個(gè)字相關(guān)(當(dāng)然也可以使用三元模型,即每個(gè)字的概率只和它前兩個(gè)字相關(guān)),簡化后
所以問題轉(zhuǎn)化為
其中CF識(shí)別信度表示當(dāng)漢字確定時(shí),其拼音為該拼音的概率,在此可以默認(rèn)為1,故問題的關(guān)鍵就是
又由概率公式
其中
可以根據(jù)統(tǒng)計(jì)的思想認(rèn)為代表和在語料庫同時(shí)出現(xiàn)的次數(shù)
代表出現(xiàn)的次數(shù)。考慮到和在語料庫中可能從來沒有同時(shí)出現(xiàn)過,因此將改寫為
。
這樣算法的思路就很清楚了,首先獲得語料庫,可以是大量的新聞稿,遍歷所以新聞稿,統(tǒng)計(jì)每個(gè)字出現(xiàn)的次數(shù)以及每兩個(gè)連續(xù)的字出現(xiàn)的次數(shù),然后讀入新的拼音句子從統(tǒng)計(jì)結(jié)果中選出最佳的漢字。需要注意的是我們需要最大化的是
而不是
也就是說需要找到是整個(gè)句子的概率最大的,而不是某個(gè)字概率最大的漢字,這一點(diǎn)可以通過動(dòng)態(tài)規(guī)劃實(shí)現(xiàn)。
以下上代碼:
記錄每個(gè)拼音對(duì)應(yīng)的漢字集
private void initPinyin(){char[] cs = Utility.readStrFromFile(Utility.HANZI_TABLE).toCharArray();List<String> ls = Utility.readListFromFile(Utility.PINYIN_TABLE);String[] ps = new String[ls.size()];String[] hs = new String[ls.size()];for (int i = 0; i < ls.size(); ++i){int border = ls.get(i).indexOf(" ");ps[i] = ls.get(i).substring(0, border);hs[i] = ls.get(i).substring(border + 1);}p_map = new HashMap<String, List<Character>>();for (int i = 1; i < cs.length; ++i){for (int j = 0; j < hs.length; ++j){if(hs[j].indexOf(cs[i]) != -1){if(!p_map.containsKey(ps[j])){p_map.put(ps[j], new ArrayList<Character>());}p_map.get(ps[j]).add(cs[i]);}}}writeMap(p_map, Utility.PINYIN_MAP); }根據(jù)語料庫進(jìn)行統(tǒng)計(jì)(語料庫為json格式)
private void initHanzi(){char[] cs = Utility.readStrFromFile(Utility.HANZI_TABLE).toCharArray();c_map = new HashMap<Character, Integer>();w_map = new HashMap<Character, Map<Character, Integer>>();for (int i = 1; i < cs.length; ++i){c_map.put(cs[i], 0);w_map.put(cs[i], new HashMap<Character, Integer>());}w_map.put('#', new HashMap<Character, Integer>());writeMap(c_map, Utility.HANZI_MAP);writeMap(w_map, Utility.TWO_HANZI_MAP); }private void updateHanzi(String news_file) {List<String> ss = Utility.readListFromFile(news_file);c_map = readMap(Utility.HANZI_MAP);w_map = readMap(Utility.TWO_HANZI_MAP);for (String s: ss) {s = s.substring(s.indexOf("{\"html\":"));JSONObject object = new JSONObject(s);String content = object.getString("html");char[] hanzi = content.toCharArray();char before = '#';for (char h : hanzi) {if (isChinese(h)) {Integer count = c_map.get(h);if (count != null) {c_map.replace(h, count + 1);if ((count = w_map.get(before).get(h)) != null) {w_map.get(before).replace(h, count + 1);} else {w_map.get(before).put(h, 1);}before = h;} else {before = '#';}} else {before = '#';}}}writeMap(c_map, Utility.HANZI_MAP);writeMap(w_map, Utility.TWO_HANZI_MAP); }使用動(dòng)態(tài)規(guī)劃進(jìn)行翻譯
public String[] predict(String pinyin){String[] ps = pinyin.split(" ");Queue<Possibility> queue = new PriorityQueue<Possibility>();queue.add(new Possibility("#", Utility.INIT_POSSIBILITY));return dynamicPlanning(ps, 0, queue); }private String[] dynamicPlanning(String[] ps, int index, Queue<Possibility> queue){if(index == ps.length){String[] result = new String[Math.min(queue.size(), Utility.OUT_SIZE)];for (int i = 0; i < result.length; ++i){result[i] = queue.poll().str.substring(1);}return result;}Possibility[] before = new Possibility[Math.min(queue.size(), Utility.MAX_SIZE)];double norm = queue.peek().p;for (int i = 0; i < before.length; ++i){before[i] = queue.poll();before[i].p /= norm;}queue.clear();List<Character> cs = p_map.get(ps[index]);for (Possibility s : before) {for (Character c : cs) {Possibility possibility = s.generateNext(c);if(!Double.isNaN(possibility.p)){queue.add(possibility);}}}return dynamicPlanning(ps, index + 1, queue); }class Possibility implements Comparable<Possibility> {String str;double p;Possibility(String str, double p) {this.str = str;this.p = p;}Possibility generateNext(char next){char before = str.charAt(str.length() - 1);return new Possibility(str + next, p * getPossibility(before, next));}private double getPossibility(char before, char next){int n_count = c_map.get(next);if(before == '#'){return n_count / Utility.RATIO;}else {int b_count = c_map.get(before);Integer integer = w_map.get(before).get(next);int bn_count = integer == null ? 0 : integer;return Utility.ALPHA * bn_count / b_count + (1 - Utility.ALPHA) * n_count / Utility.RATIO;}}public int compareTo(Possibility o) {return Double.compare(o.p, p);} }按概率高低輸出概率最高的5個(gè)漢字句子
項(xiàng)目地址https://github.com/ChenErTong/PinYin
總結(jié)
以上是生活随笔為你收集整理的基于贝叶斯公式的拼音输入法二元模型实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【多媒体基础知识】 --- 什么是流媒体
- 下一篇: 使用unity完成简单的打地鼠游戏2D制