1. 程式人生 > 實用技巧 >詞性標註維特比演算法實現

詞性標註維特比演算法實現

基於前幾篇文章對維特比演算法的說明,此文對維特比演算法進行實現,並基於維特比演算法實現給定語句的詞性標註。關於\(pi,A,B\)的說明參考文章詞性標註語料預處理實戰,維特比相關演算法說明參考詞性標註維特比演算法介紹

def log(v):
    if v == 0:
        return np.log(v+0.000001)
    return np.log(v)


def vertibe(x, pi, A, B):
    """
    :param x:輸入的待預測詞性的文字,例如 "I like NLP"
    :param pi:初始的詞性概率
    :param A:給定詞性,每個單詞的概率
    :param B:詞性之間的狀態轉移概率
    :return:
    """
    # 處理輸入的文字數,獲取輸入文字在上文處理的id號
    x = [word2id[word] for word in x.split(" ")]
    # 獲取輸入文字分詞後的長度
    T = len(x)
    # dp[i][j] 標識第i個詞的詞性為第j個詞性
    dp = np.zeros((T, N))

    ptr = np.array([[0 for x in range(N)] for y in range(T)])
    # 計算第一個詞在給定詞性的概率
    for j in range(N):
        dp[0][j] = log(pi[j]) + log(A[j][x[0]])

    for i in range(1, T):   # 迴圈每一個單詞
        for j in range(N):  # 每個詞性
            dp[i][j] = -99999999   # 設定一個很小的分值,作為後續計算每次的計算比較值
            for k in range(N):  # 迴圈每個詞性,計算從上一個詞性到當前詞性的值
                score = dp[i-1][k] + log(B[k][j]) + log(A[j][x[i]])
                if score > dp[i][j]:
                    dp[i][j] = score
                    ptr[i][j] = k   # 記錄得分最高的值是從上一層的那個節點過來的
    # 把最好的詞性標註序列打印出來
    best_seq = [0]*T
    # step 1 找出對應於最後一個詞的詞性
    best_seq[T-1] = np.argmax(dp[T-1])
    # step 2 通過迴圈,從後到前依次求出每個單詞的詞性
    for i in range(T-2, -1, -1):
        best_seq[i] = ptr[i+1][best_seq[i+1]]

    # 列印預測的詞性序列
    for i in range(len(best_seq)):
        print(id2tag[best_seq[i]])

x = "Newsweek , trying to keep pace with rival Time magazine , announced new advertising rates for 1990"

vertibe(x, pi, A, B)

執行結果如下

NNP
,
VBG
TO
VB
NN
IN
JJ
NN
NN
,
VBD
JJ
NN
NNS
IN
CD

該測試語料是從訓練語料中提取的,我們看下訓練語料的標註,如下所示

Newsweek/NNP
,/,
trying/VBG
to/TO
keep/VB
pace/NN
with/IN
rival/JJ
Time/NNP
magazine/NN
,/,
announced/VBD
new/JJ
advertising/NN
rates/NNS
for/IN
1990/CD

前面是詞,後面是該詞的詞性,從對比看,詞性標註的預測結果相對準確。

備註:此章節實現參考了貪心學院的相關視訊課程和程式碼,在此標註。