python實現三元語言模型與輸入法推薦

語言模型的作用是在大量的訓練樣例中,給出一個句子求出概率,其中應用的技術有平滑、 統計語言模型。

假設S表示某一個有意義的句子,由一連串特定順序排列的詞w1、w2、w3、...、wn組成,利用條件概率公式,能夠得到:

P(S)=P(W1,W2,W3,...,Wn)

=P(W1)P(W2|W1)P(W3|W1,W2)…P(Wn|W1,W2,…,Wn-1)

P(W1)    —— 第一個詞W1出現的概率

P(W2|W1)—— 已知第一個詞W1的前提下,第二個詞W2出現的概率

根據馬爾科夫模型,

    任意一個詞出現的概率只與它前面出現的有限的1個或着i個詞有關。

如句子,“我愛打籃球”的概率:

二元模型:P(我) * P(愛|我) * P(打|愛) * P(籃球|打)

三元模型:P(我,愛) * P(打|我,愛) * P(籃球|愛,打)

P(我,愛) = P(我) * (愛|我)

 

•     Goal:compute the probability of a sentence or sequence of words:

     P(W) = P(w1,w2,w3,w4,w5…wn)

•     Related task: probability of an upcoming word:

      P(w5|w1,w2,w3,w4)

•     Amodel that computes either of these:

          P(W)     or    P(wn|w1,w2…wn-1)          is called alanguage model.

•     Better:the grammar       But languagemodel or LM is standard


根據語言模型和統計結果確定候選集,完成推薦下一個詞的任務。

 

實踐步驟:

1、獲取語料庫資料

2、分詞統計

3、以一定格式輸出到文本中

4、讀入文本

5、分詞

6、查找文本中的資料

7、排序

8、輸出前5個結果

 

主要的問題包括:

1、需要大量的多領域語料庫。

2、運行效率和存儲空間,是時間和空間的折衷處理。

3、可以加入詞性考慮。

 

代碼:

 獲取一個文件夾下全部文件:

#讀取目錄內所有文件,返回文件路徑列表
def readAllFiles(baseDir, fileList):
    filelist=os.listdir(baseDir)
    for dir in filelist:
        if os.path.isdir(baseDir+'/'+dir):
            readAllFiles(baseDir+'/'+dir, fileList)
        else:
            fileList.append(baseDir+'/'+dir)

讀取文件:

def readFile(url):
    dataset = open(url, 'r+', encoding='utf-8').read()


核心統計詞頻,其中包含去除文件中的詞性標註:

#統計詞頻,三個單詞
def frequency(sentence, dicts, N=2, replace=True, split_string='  '):
	#排除詞性標註
    if replace==True:
        sentence = sentence.replace('\n', '').replace('/', '')
        for alp in alp_table:
            sentence=sentence.replace(alp, '')
    lists=sentence.split('  ')
    preword_list=[]
    total_word=0
    #list是當前的sentence詞語集合的列表
    for word in lists:
    	#代表句子的結尾
        if word in symbol_table:
            temp = dicts
            for preword in preword_list:
                temp = temp[pre·	word]
            if preword_list!=[]:
                temp[' '] += 1
            preword_list = []
            continue

        #去除詞語中的無意義標註,如胖子&#中的&,#
        for ch in forbidden_table:
            if ch in word:
                word.replace(ch, '')

        if word not in word_dict:
            word_dict[word]=1
        else:
            word_dict[word]+=1

        total_word+=1
        if len(preword_list)==N:
            temp=dicts
            for preword in preword_list:
                temp=temp[preword]
            temp[' ']+=1
            preword_list.pop(0)

        temp=dicts
        for preword in preword_list:
            if preword not in temp:
                temp[preword]={' ':0}
            temp=temp[preword]
        if word not in temp:
            temp[word]={' ':0}
        preword_list.append(word)
    return total_word

把字典轉換爲格式化字符串,把字典轉換爲方便排序的列表:

def dict2str(dicts):
    result=""
    for dic in dicts:
        if dic==' ':
            continue
            #result+=dic+' '+str(dicts[dic])+'\n'
        else:
            temp=dicts[dic]
            for dic2 in temp:
                if dic2 == ' ':
                    result+=dic+' '+str(temp[dic2])+'\n'
                else:
                    temp2=temp[dic2]
                    for dic3 in temp2:
                        if dic3==' ':
                            result+=dic+' '+dic2+' '+str(temp2[dic3])+'\n'
                        else:
                            result+=dic+' '+dic2+' '+dic3+' '+str(temp2[dic3][' '])+'\n'
    return result

def dict2list(dic:dict):
    ''' 將字典轉化爲列表 '''
    keys = dic.keys()
    vals = dic.values()
    lst = [(key, val) for key, val in zip(keys, vals)]
    return lst

運行函數:

import os
alp_table = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
             'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u','v',
             'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
             'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
             'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_']
symbol_table = [',', '。', '!', '?', ';', '、', '/', '(', ')', '《', '》', '——', '\'', '\"']+alp_table
num_table = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']


forbidden_table = ['&','#',',', '。', '!', '?', ';', '、', '/', '(', ')', '《', '》', '——', '\'', '“', '”', '【', '】']+symbol_table+alp_table+num_table
dataset=""
word_dict={}
if __name__=='__main__':
    dicts = {}
    files_list = []
    # 讀取全部文件
    readAllFiles('./corpus2/corpus', files_list)
    # 對每個文件進行識別單詞操作
    for file in files_list:
        fp = open(file, 'r+')
        frequency(fp.read(), dicts, N=3)
        fp.close()

    fp = open('dict.txt', 'a')
    word_dict=sorted(word_dict.items(), key=lambda x:x[1],reverse=True)
    for k in word_dict:
        fp.write(k[0]+' '+str(k[1])+'\n')
    #print(len(lst))
    fp.close()


預處理結束後,進行第二步查詢結果:

核心函數,預測,功能是讀入文件,進行統計排序:

fp=open('result3.txt', 'r')
dataset=fp.read().split('\n')
fp.close()
#輸入詞組列表後預測
def Predict2(sentence, urlPath='result3.txt'):
    word_list=" ".join(jieba.cut(sentence, HMM=False)).split(' ')
    if (len(word_list) <= 0):
        return False
    result_dict={}
    start=False
    if len(word_list)==1:
        for data in dataset:
            words = data.split(' ')
            if len(words)<3:
                continue
            if word_list[0]==words[0]:
                start=True
                if words[1] not in result_dict:
                    if len(words) == 3:
                        result_dict[words[1]] = int(words[2])
                    else:
                        result_dict[words[1]] = int(words[3])
                else:
                    if len(words) == 3:
                        result_dict[words[1]] += int(words[2])
                    else:
                        result_dict[words[1]] += int(words[3])
            '''else:
                if start==True:
                    break'''
    else:
        for data in dataset:
            words = data.split(' ')
            if len(words)!=4:
                continue
            if word_list[-2]==words[0] and word_list[-1]==words[1]:
                #start=True
                result_dict[words[2]] =int(words[3])
            '''else:
                if start==True:
                    break'''
    result_list = dict2list(result_dict)
    result_list.sort(key=lambda item:item[1], reverse=True)
    return result_list

最後,輸入句子,利用jieba分詞,可以得到最終結果:

alp_table = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
             'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u','v',
             'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
             'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
             'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '_']
symbol_table = [',', '。', '!', '?', ';', '、', '/', '(', ')', '《', '》', '——', '\'', '\"', ';']+alp_table
num_table = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']


forbidden_table = ['&','#',',', '。', '!', '?', ';', '、', '/', '(', ')', '《', '》', '——', '\'', '“', '”', '【', '】']+symbol_table+alp_table+num_table

#begin = datetime.datetime.now()
#list=Predict('坐')
#end = datetime.datetime.now()
#print(end-begin)
if __name__=='__main__':
    print('按q退出程序')
    while True:
        s = input('輸入句子:')
        if (s == 'q'):
            break
        word_list = " ".join(jieba.cut(s, HMM=False)).split(' ')
        start=datetime.datetime.now()
        lkk = Predict2(s)
        lst=[]
        for word in lkk:
            ok=True
            for ch in forbidden_table:
                if ch in word[0]:
                    ok=False
                    break
            if(ok==True):
                lst.append(word)
                if(len(lst)==5):
                    break


        length=len(lst)
        if length < 5:
            length = 5
            fp = open('dict.txt', 'r')
            lines = fp.readlines()
            for line in lines:
                templst = line.split(' ')
                word=templst[0]
                templst[1] = templst[1].split('\n')[0]
                if (word in lst) or (word in word_list):
                    continue
                ok = True
                for ch in forbidden_table:
                    if ch in word:
                        ok = False
                        break
                if (ok == True):
                    lst.append(templst)
                if (len(lst) == 5):
                    break
            fp.close()
        result = "推薦: "
        for i in range(length):
            result += lst[i][0] + str(lst[i][1]) + '  '
        print(result + '\n')
        end = datetime.datetime.now()
        print(end - start)

實現效果:


文件保存形式:



到此完成推薦詞語的任務,記得安裝jieba分詞,可以免去輸入分詞。

有需要語料庫的朋友可以留言告知。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章