1.2 Bigram计算句子的概率python实现

Posted 炫云云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1.2 Bigram计算句子的概率python实现相关的知识,希望对你有一定的参考价值。


上一节请看:

1.1 文本表示——词袋法:one-hot、TF-IDF、n-gram、神经概率语言模型

条件概率计算公式

条件概率是指事件A在事件B发生的条件下发生的概率。条件概率表示为: P ( A ∣ B ) \\mathrm{P}(\\mathrm{A} \\mid \\mathrm{B}) P(AB) 。若只有两个事件 A , B \\mathrm{A}, \\mathrm{B} A,B, 则有如下公式:
P ( A ∣ B ) = P ( A B ) P ( B ) P(A \\mid B)=\\frac{P(A B)}{P(B)} P(AB)=P(B)P(AB)

Bigram语言模型

Bigram也称为一节马尔科夫链, 通俗的讲, 我们可以认为这是一个词的概率实际上只是跟前边的词有关那么就可以有以下的方程:
p ( s ) = ∏ i = 1 l p ( w i ∣ w 1 ⋯ w i − 1 ) ≈ ∏ i = 1 l p ( w i ∣ w i − 1 ) p(s)=\\prod_{i=1}^{l} p\\left(w_{i} \\mid w_{1} \\cdots w_{i-1}\\right) \\approx \\prod_{i=1}^{l} p\\left(w_{i} \\mid w_{i-1}\\right) p(s)=i=1lp(wiw1wi1)i=1lp(wiwi1)
同时为了保证条件概率在 i = 1 \\mathrm{i}=1 i=1 时有意义, 同时为了保证句子内所有字符串的概率和为 1, 可以在句子首尾两端增加两个标志: < B O S   W 1 W 2 . . . W n   E O S > <BOS~ W_1 W_2...W_n ~EOS> <BOS W1W2...Wn EOS> 为了估计 P ( W i ∣ W i − 1 ) P\\left(W_{i} \\mid {W}_{i-1}\\right) P(WiWi1)的条件概率我们计算出 W i − 1 , W i W_{i-1}, W_{i} Wi1,Wi 的词汇出现的频率然后得出概率, 公式如下:
P ( W i ∣ W i − 1 ) = C ( W i − 1 , W i ) C ( W i − 1 ) P\\left(W_{i} \\mid {W}_{i-1}\\right)=\\frac{C\\left(W_{i-1}, W_{i}\\right)} {C\\left(W_{i-1}\\right)} P(WiWi1)=C(Wi1)C(Wi1,Wi)
计算出每个词汇的概率后,便可根据公式求得句子的概率。

目标

语料库: 研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。

测试句子:研究生物专业是他的首选目标

使用二元模型以分词模式计算出测试句子的概率。

[‘BOS’, ‘研究’, ‘生物’, ‘专业’, ‘是’, ‘他’, ‘的’, ‘首选’, ‘目标’, ‘EOS’]

P ( T ) = P ( 研 究 ∣ B O S ) P ( 生 物 ∣ 研 究 ) P ( 专 业 ∣ 生 物 ) P ( 是 ∣ 专 业 ) P ( 他 ∣ 是 ) P ( 的 ∣ 他 ) P ( 首 选 ∣ 的 ) P ( 目 标 ∣ 首 选 ) P ( E O S ∣ 目 标 ) P(T) = P(研究|BOS)P(生物|研究)P(专业|生物)P(是|专业)P(他|是)P(的|他) P(首选|的) P(目标|首选) P(EOS|目标) P(T)=P(BOS)P(P()P(P(P()P()P()P(EOS)

将句子变为"BOSxxxxxEOS"这种形式

正则表达式:re.match、re.search、re.sub、re.compile、findall、re.finditer、re.split

import jieba
import re
#语料句子
sentence_ori="研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。"
#测试句子

sentence_test="研究生物专业是他的首选目标"

#任务:完成对2-gram模型的建立,计算测试句子概率并输出结果


punc = r"""!  ?。"#$%&'()*+,-/:;<=>@[\]^_`{|}~⦅⦆「」、、〃》「」『』【】〔〕〖〗〘〙〚〛〜〝〞〟〰〾〿–—‘’‛“”„‟…‧﹏.#$%&'()*+,-./:;<=>?@[\\]^_`{|}~“”?,!【】()、。:;’‘……¥·"""


punctuation_map = dict((ord(char), "EOSBOS") for char in punc)  
new_s=sentence_ori.translate(punctuation_map)
print(new_s)


def Modify(s):
    #将结尾标点符号截掉
    if s[-1] in (r"[%s]+"%punc):
        s = s[:-1]  #截取字符串从开头到倒数一个字符的子串

    #添加起始符BOS和终止符EOS   
    s_modify1 = re.sub(r"[%s]+"%punc, "EOS BOS", s)   ## r'\\w+'为正则表达式,匹配多个英文单词或者数字  
    s_modify2="BOS"+s_modify1+"EOS"
    return s_modify2

train_Modifys=Modify(sentence_ori)
print(train_Modifys)

test_Modifys =Modify(sentence_test) 

研究生物很有意思EOSBOS他大学时代是研究生物的EOSBOS生物专业是他的首选目标EOSBOS他是研究生EOSBOS
BOS研究生物很有意思EOS BOS他大学时代是研究生物的EOS BOS生物专业是他的首选目标EOS BOS他是研究生EOS

分词并统计词频

意境级讲解 jieba分词和词云、关键词抽取:TextRank、TF-IDF

def Partition_Statistics(s, dicts = None):
    jieba.suggest_freq(('BOS','EOS'), True)#分开
    s = jieba.cut(s, HMM = False)  #精确模式,自动计算的词频在使用 HMM 新词发现功能时可能无效,所以设为False
    format_s = ",".join(s)
    #将词按","分割后依次填入数组
    lists = [i.strip() for i in format_s.split(",") if i  not in punc ]
    #统计词频
    if dicts != None:
        for word in lists:
            if word not in dicts:
                dicts[word] = 1
            else:
                dicts[word] += 1               
    return lists , dicts


train_seg,train_count = Partition_Statistics(train_Modifys,dicts = {})
print(train_seg  )
print(train_count)
test_seg,test_count = Partition_Statistics(test_Modifys,dicts = {})

['BOS', '研究', '生物', '很', '有意思', 'EOS', 'BOS', '他', '大学', '时代', '是', '研究', '生物', '的', 'EOS', 'BOS', '生物', '专业', '
是', '他', '的', '首选', '目标', 'EOS', 'BOS', '他', '是', '研究生', 'EOS']
{'BOS': 4, '研究': 2, '生物': 3, '很': 1, '有意思': 1, 'EOS': 4, '他': 3, '大学': 1, '时代': 1, 
'是': 3, '的': 2, '专业': 1, '首选': 1, '目标': 1, '研究生': 1}

Bigram

二元语法,比较两个数列,求一个词在历史条件下出现的频数

 def CompareList(ori_list,test_list):
    #申请空间
    count_list=[0]*(len(test_list)-1)
    #遍历测试的字符串
    for i in range(0, len(test_list)-1):
        #遍历语料字符串,因为是二元语法,不用比较语料字符串的最后一个字符
        for j in range(0,len(ori_list)):
            #如果测试的第一个词和语料的第一个词相等则比较第二个词
            if test_list[i]==ori_list[j]:
                if test_list[i+1]==ori_list[j+1]:
                    count_list[i]+=1
    return count_list

def Probability(test_list,count_list,ori_dict):
    #概率值为p
    p=1
    for i in range(len(count_list)): 
        p *=(float(count_list[i])/float(ori_dict[test_list[i]]))
    return p


count_list = CompareList(train_seg, test_seg)
print(count_list)
p = Probability(train_seg,count_list,train_count)
print(p)
[1, 2, 1, 1, 1, 1, 1, 1, 1]
0.001736111111111111

这样就实现了以分词模式”['BOS', '研究', '生物', '专业', '是', '他', '的', '首选', '目标', 'EOS']”计算出现句子的概率,为0.001736111111111111。

以上是关于1.2 Bigram计算句子的概率python实现的主要内容,如果未能解决你的问题,请参考以下文章

实验一:训练Bigram模型并预测句子概率|自然语言

1.3 n-gram平滑算法:Good-Turning拉普拉斯平滑

理解循环神经网络的来龙去脉

NLP_Stanford课堂语言模型

如何在给定上下文的句子中获取特定标记(单词)的概率

朴素贝叶斯从理论到Python实现再到实战.整理