從n-gram中文文本糾錯,到依存樹中文語法糾錯以及同義詞查找

前記

        本文簡單地講解如何使用n-gram模型結合漢字拼音來做中文錯別字糾錯,而後介紹最短編輯距離在中文搜索糾錯方面的應用;最後從依賴樹入手講解如何做文本長距離糾錯(語法糾錯),並從該方法中獲得一種啓示,利用依賴樹的特色結合ESA算法來作同義詞的查找。html

n-gram模型

        在中文錯別字查錯情景中,咱們判斷一個句子是否合法能夠經過計算它的機率來獲得,假設一個句子S = {w1, w2, ..., wn},則問題能夠轉換成以下形式:java

        P(S)被稱爲語言模型,即用來計算一個句子合法機率的模型。ios

        可是使用上式會出現不少問題,參數空間過大,信息矩陣嚴重稀疏,這時就有了n-gram模型,它基於馬爾科夫模型假設,一個詞的出現機率僅依賴於該詞的前1個詞或前幾個詞,則有算法

(1)一個詞的出現僅依賴於前1個詞,即Bigram(2-gram):less

(2)一個詞的出現僅依賴於前2個詞,即Trigram(3-gram):jsp

        當n-gram的n值越大時,對下一個詞的約束力就越強,由於提供的信息越多,但同時模型就越複雜,問題越多,因此通常採用bigram或trigram。下面舉一個簡單的例子,說明n-gram的具體使用:函數

        n-gram模型經過計算極大似然估計(Maximum Likelihood Estimate)構造語言模型,這是對訓練數據的最佳估計,對於Bigram其計算公式以下:
性能

        對於一個數據集,假設count(wi)統計以下(總共8493個單詞):測試

        而count(wi, wi-1)統計以下:ui

        則Bigram機率矩陣計算以下:

        句子「I want to eat Chinese food」成立的機率爲:

P(I want to eat Chinese food) = P(I) * P(want|I) * P(to|want) * P(eat|to) * P(Chinese|eat) * P(food|Chinese)

= (2533/8493) * 0.33 * 0.66 * 0.28 * 0.021 * 0.52。

        接下來咱們只須要訓練肯定一個閥值,只要機率值≥閥值就認爲句子合法。

        爲了不數據溢出、提升性能,一般會使用取log後使用加法運算替代乘法運算,即

log(p1*p2*p3*p4) = log(p1) + log(p2) + log(p3) + log(p4)

        能夠發現,上述例子中的矩陣存在0值,在語料庫數據集中沒有出現的詞對咱們不能就簡單地認爲他們的機率爲0,這時咱們採用拉普拉斯矩陣平滑,把0值改成1值,設置成該詞對出現的機率極小,這樣就比較合理。

        有了上面例子,咱們能夠拿n-gram模型來作選擇題語法填空,固然也能夠拿來糾錯。中文文本的錯別字存在局部性,即咱們只須要選取合理的滑動窗口來檢查是否存在錯別字,下面舉一個例子:

        咱們可使用n-gram模型檢查到「穿」字打錯了,這時咱們將「穿」字轉換成拼音「chuan」,再從詞典中查找「chuan」的候選詞,一個一個試填,用n-gram檢查,看是否合理。這就是n-gram模型結合漢字拼音來作中文文本錯別字糾錯了。漢字轉拼音可使用Java庫pinyin4j

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

public class Keyven {
    public static void main(String[] args) {
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

        String str = "我愛天然語言處理,Keyven";
        System.out.println(str);
        String[] pinyin = null;
        for (int i = 0; i < str.length(); ++i) {
            try {
                pinyin = PinyinHelper.toHanyuPinyinStringArray(str.charAt(i),
                        format);
            } catch (BadHanyuPinyinOutputFormatCombination e) {
                e.printStackTrace();
            }

            if (pinyin == null) {
                System.out.print(str.charAt(i));
            } else {
                if (i != 0) {
                    System.out.print(" ");
                }
                System.out.print(pinyin[0]);
            }
        }
    }
}


最短編輯距離

        固然,現實生活中也存在漢字拼音沒打錯,是詞語選錯了;或者n-gram檢查合理但詞語不存在,例如:


        這時就用到最短編輯距離了,對於這種熱搜詞,咱們僅需記錄n-Top,而後用最短編輯距離計算類似度,提供類似度最高的那個候選項就能夠了。

        編輯距離,又稱Levenshtein距離,是指兩個字串之間,由一個轉成另外一個所需的最少編輯操做次數。許可的編輯操做包括將一個字符替換成另外一個字符,插入一個字符,刪除一個字符。例如將kitten一字轉成sitting
    sitten (k→s)
    sittin (e→i)
    sitting (→g)

        俄羅斯科學家Vladimir Levenshtein在1965年提出這個概念。它是一種DP動態規劃算法,在POJ或ACM算法書上有相似的題目。主要思想以下:

        首先定義這樣一個函數Edit(i, j),它表示第一個字符串的長度爲i 的子串到第二個字符串的長度爲j 的子串的編輯距離。顯然能夠有以下動態規劃公式:
    if (i == 0 且 j == 0),Edit(i, j) = 0
    if (i == 0 且 j > 0),Edit(i, j) = j
    if (i > 0 且j == 0),Edit(i, j) = i
    if (i ≥ 1  且 j ≥ 1) ,Edit(i, j) = min{ Edit(i-1, j) + 1, Edit(i, j-1) + 1, Edit(i-1, j-1) + F(i, j) },

        其中,當第一個字符串的第i 個字符不等於第二個字符串的第j 個字符時,F(i, j) = 1;不然,F(i, j) = 0。

#include <iostream>
#include <string.h>

using namespace std;

#define min(a,b) (a<b?a:b)
#define min3(a,b,c) (a<min(b,c)?a:min(b,c))

int main()
{
    /*
    AGTCTGACGC
    AGTAAGTAGGC

    sailn
    failing
    */
    char astr[100], bstr[100];
    int dist[100][100];
    memset(astr, '\0', sizeof(astr));
    memset(bstr, '\0', sizeof(bstr));
    memset(dist, 0, sizeof(dist));

    gets(astr);
    gets(bstr);

    int alen = strlen(astr);
    int blen = strlen(bstr);
    for (int i = 0; i <= alen; i++)
    {
        dist[i][0] = i;
    }
    for (int i = 0; i <= blen; i++)
    {
        dist[0][i] = i;
    }

    for (int i = 1; i <= alen; i++)
    {
        for (int j = 1; j <= blen; j++)
        {
            int d = (astr[i - 1] != bstr[j - 1]) ? 1 : 0;
            dist[i][j] = min3(dist[i - 1][j] + 1, dist[i][j - 1] + 1, dist[i - 1][j - 1] + d);
        }
    }

    for (int i = 0; i <= alen; i++)
    {
        for (int j = 0; j <= blen; j++)
        {
            printf("%d ", dist[i][j]);
        }
        printf("\n");
    }

    printf("%d\n", dist[alen][blen]);

    system("pause");
    return 0;
}

中文語法糾錯

        以前參加了中文語法錯誤診斷評測CGED(ACL-IJCNLP2015 workshop)比賽,我負責的是Selection 部分,咱們來看官方給出的樣例(Redundant、Missing、Selection、Disorder分別對應4種語法錯誤):

        比勝過程中有想到使用依存樹來解決Selection(語法搭配錯誤)問題,語法搭配與其說是語法範疇,倒不如說是語義概念,例如「那個電影」咱們判斷「個」錯了是依據「電影」一詞來判斷,又如「吳先生是修理腳踏車的拿手」判斷「拿手」錯了是依據「是」一字,「拿手」是動詞,怎麼能採用「是+名詞」結構呢?可是當時事情比較多各類手忙腳亂前途未卜,因此沒作出來。後來上網查論文看到一篇《基於n-gram及依存分析的中文自動差錯方法》,記得是2年前看到過的,當時對依存樹還不理解因此沒在乎論文的後半部,如今理解了,寫東西也有個理論支撐,沒想到想法好有緣分^_^。

        詞與詞之間的搭配是看二者之間的語義關聯強度,而依存樹的邊正能夠用來體現這種語義關聯度,若是一個句子存在Selection語法錯誤,那麼建成依存樹也應該存在一條邊是不合理的,咱們能夠用這條邊來判斷是否出現了語法錯誤。在上述論文中做者將其稱之爲用來做長距離的中文糾錯,而n-gram則是短距離中文糾錯。

        至於怎樣利用已有知識,創建領域知識庫,咱們能夠跑一遍正確的語料庫數據集,統計那些語法正確的句子的依存樹邊... ...CGED那個比賽所給的訓練集有點奇怪,這個也是致使比勝過程不理想沒把依存樹想法作出來的緣由。我從新從網上找來了幾個測試樣例(語言學專業的課件PPT),咱們來看一下再看如何拿依存樹來作同義詞聚類。利用依存樹作Selection語法偵錯是有了,但是還要糾錯呢,怎麼實現一種糾錯算法呢,固然是同義詞替換了,會產生Selection類錯誤通常都是同義詞誤用。我曾經拿HIT-IRLab-同義詞詞林(擴展版) 對比,效果不是很好,因此就有了後來的同義詞聚類想法。

依存樹同義詞查找

        以前有接觸過同義詞聚類的論文,其中印象比較深入的一篇是《 Computing Semantic Relatedness using Wikipedia-based Explicit Semantic Analysis 》,也就是ESA(Explicit Semantic Analysis)算法。ESA的主要思想就是,將一個Wiki詞條當作一個主題概念,而後將詞條下的解釋文本先用TF-IDF逆文檔頻率過濾分詞,再用倒排索引創建成(word-Topic),這樣就能夠構造主題向量,咱們能夠用這些主題向量來作語義類似度計算,完成同義詞的查找。

        可是這種工做對於我來講有點難以完成,後來在看Selection平行語料庫時,發現同樣有意思的東西,就是上圖中標成黃色的邊,瞬間突發奇想,是否是能夠拿這些依存邊做爲一個Topic,利用倒排索引創建主題向量,這樣就能夠造出一大堆豐富的原始特徵,而後再找個算法做特徵選擇過濾,再完成同義詞查找... ...

Reference

基於n-gram及依存分析的中文自動差錯方法(馬金山,劉挺,李生)

Computing Semantic Relatedness using Wikipedia-based Explicit Semantic Analysis

斯坦福大學天然語言處理第四課「語言模型(Language Modeling)」

天然語言處理 —— 讓輸入法變得更聰明

百度筆試題目剖析——拼寫糾錯

採用Stanford Parser進行中文語法解析

Stanford Parser

使用pinyin4j

第五章 n-gram語言模型

編輯距離及編輯距離算法

pinyin4j-2.5.0.jar 免費下載最新版

利用維基百科計算語義類似度【多媒體論文閱讀】

中文語法錯誤診斷評測CGED(ACL-IJCNLP2015 workshop)

相關文章
相關標籤/搜索