Part 1.2 基於維特比演算法來優化上述流程

棉馬咪發表於2020-12-19

基於維特比演算法來優化上述流程

這一部分的程式碼就是構建詞典,和前面一篇文章是一樣的。

def create_dic(file_path):
    workbook = xlrd.open_workbook(file_path)
    booksheet = workbook.sheet_by_index(0)
    col_values = booksheet.col_values(0)
    dict_words = {}
    max_len_word = 0
    for word in col_values:
        dict_words[word] = 0.00001
        if max_len_word < len(word):
            max_len_word = len(word)
    print(len(dict_words))
    print(max_len_word)
    return dict_words, max_len_word

dic_words, max_len_word = create_dic('XXXXXX\綜合類中文詞庫.xlsx')
word_prob = {"北京": 0.03, "的": 0.08, "天": 0.005, "氣": 0.005, "天氣": 0.06, "真": 0.04, "好": 0.05, "真好": 0.04, "啊": 0.01,
             "真好啊": 0.02,
             "今": 0.01, "今天": 0.07, "課程": 0.06, "內容": 0.06, "有": 0.05, "很": 0.03, "很有": 0.04, "意思": 0.06, "有意思": 0.005,
             "課": 0.01,
             "程": 0.005, "經常": 0.08, "意見": 0.08, "意": 0.01, "見": 0.005, "有意見": 0.02, "分歧": 0.04, "分": 0.02, "歧": 0.005}

for key, value in word_prob.items():
    dic_words[key] = value

維特比演算法簡介

在這裡插入圖片描述
僅以圖中為例:
根據所有的可能的從開始->結束的路徑
[1]先考慮路徑為1的可能組合:經——常——有——意——見——分——歧
[2]再考慮路徑為2的可能組合:經常、意見、分期
[3]再考慮路徑為3的可能組合:有意見、見分期
這樣就構成了所有的可能組合,程式碼如下所示:

def create_graph(input_str):
    N = len(input_str)
    graph = {}
    for idx_end in range(1, N + 1):
        temp_list = []
        max_split = min(idx_end, max_len_word)
        for idx_start in range(idx_end - max_split, idx_end):
            word = input_str[idx_start:idx_end]
            if word in dic_words:
                temp_list.append(idx_start)
        graph[idx_end] = temp_list
    return graph 
-------------------------------------------
舉例:
create_graph("北京的天氣")
{1: [0], 2: [0, 1], 3: [2], 4: [3], 5: [3, 4]}
結果的意思是:
1代表"北",那麼往前推,所有的可能的搭配就是"北",其對於的起始下標是0
2代表"京",那麼往前推,所有的可能的搭配就是"北-京",起始下標是0"京",起始下標是1
3代表"的",那麼往前推,所有的可能的搭配就是"的",其對於的起始下標是2
4代表"天",那麼往前推,所有的可能的搭配就是"天",其對於的起始下標是3
5代表"氣",那麼往前推,所有的可能的搭配就是"天-氣",起始下標是3"氣",起始下標是4
總結:
這裡的做法就是找到到了所有的,到當前單詞的所有可能路徑,有些是一個單詞(本身),有些是2個單詞(北京),有些是三個詞語(有意見),並記錄了他們的序列。

經過上面找到了所有的到達某個詞的所有可能的搭配,現在就是要找到一條路徑:

def word_segment_viterbi(input_str):
    graph = create_graph(input_str)
    N = len(input_str)
    m = [np.inf] * (N + 1) # 用於存放最短距離
    m[0] = 0 # 
    last_index = [0] * (N + 1) # 用於存放到達某一個點的上一個位置點
    for idx_end in range(1, N + 1):
        for idx_start in graph[idx_end]: #對所有的起始位置進行遍歷
        	# 在當前位置上所能匹配的單詞,加上起始位置單詞的值。例如
        	# 北京的天氣:能與氣匹配的是——天氣,在加上到達天的最短距離
            log_prob = round(-1 * np.log(dic_words[input_str[idx_start:idx_end]])) + m[idx_start]
            if log_prob < m[idx_end]:
                m[idx_end] = log_prob
                last_index[idx_end] = idx_start
    # 根據last_index 陣列,一步步往前找到所需要的序號即可
    best_segment = []
    i = N
    while True:
        best_segment.insert(0, input_str[last_index[i]:i])
        i = last_index[i]
        if i == 0:
            break
    return best_segment


print(word_segment_viterbi("北京的天氣真好啊"))
print(word_segment_viterbi("今天的課程內容很有意思"))
print(word_segment_viterbi("經常有意見分歧"))
'''

'''

相關文章