• N元语言模型


    第1关:预测句子概率

    任务描述

    本关任务:利用二元语言模型计算句子的概率

    相关知识

    为了完成本关任务,你需要掌握:1.条件概率计算方式。 2.二元语言模型相关知识。

    条件概率计算公式

    条件概率是指事件A在事件B发生的条件下发生的概率。条件概率表示为:P(A|B)。若只有两个事件A,B,则有如下公式:

    ,

    二元语言模型

    二元语言模型也称为一节马尔科夫链,通俗的讲,我们可以认为这是一个词的概率实际上只是跟前边的词有关,那么就可以有以下的方程:

    ,

    同时为了保证条件概率在 i=1 时有意义,同时为了保证句子内所有字符串的概率和为 1,可以在句子首尾两端增加两个标志: 为了估计P(WI|WI-1)的条件概率,我们计算出wi-1,wi的词汇出此案的频率然后进行归一化,公式如下:

    ,

    计算出每个词汇的概率后,便可根据公式求得句子的概率。

    编程要求

    根据提示,在右侧编辑器补充代码,计算并输出测试语句的概率

    测试说明

    平台会对你编写的代码进行测试: 语料库:

     
    
    1. 研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。

    测试输入:

    1. 研究生物专业是他的首选目标

    预期输出:

    1. 0.004629629629629629
    1. import jieba
    2. jieba.setLogLevel(jieba.logging.INFO)
    3. # 将句子变为"BOSxxxxxEOS"这种形式
    4. def reform(sentence):
    5. if sentence.endswith("。"):
    6. sentence = sentence[:-1]
    7. sentence = sentence.replace("。", "EOSBOS")
    8. sentence = "BOS" + sentence + "EOS"
    9. return sentence
    10. # 分词并统计词频
    11. def segmentation(sentence, dic):
    12. jieba.suggest_freq("BOS", True)
    13. jieba.suggest_freq("EOS", True) # 让jieba库知道"BOS""EOS"这两个词的存在,并记录它们的出现频率
    14. lists = jieba.lcut(sentence, HMM=False) # 当输入的文本比较短时,隐马尔科夫模型的效果可能会下降,导致分词结果不准确
    15. if dic is not None:
    16. for word in lists:
    17. if word not in dic:
    18. dic[word] = 1
    19. else:
    20. dic[word] += 1
    21. return lists
    22. # 比较两个数列,二元语法
    23. def compareList(ori_list, tes_list):
    24. count_list = [0] * len(tes_list)
    25. for t in range(len(tes_list)-1):
    26. for n in range(len(ori_list)-1):
    27. if tes_list[t] == ori_list[n]:
    28. if tes_list[t+1] == ori_list[n+1]:
    29. count_list[t] += 1
    30. return count_list
    31. # 计算概率
    32. def probability(tes_list, ori_dic, count_list):
    33. flag = 0
    34. p = 1
    35. del tes_list[-1]
    36. for key in tes_list:
    37. p *= float(count_list[flag]) / float(ori_dic[key])
    38. flag += 1
    39. return p
    40. if __name__ == "__main__":
    41. # 语料句子
    42. sentence_ori = "研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。"
    43. ori_dict = {}
    44. # 测试句子
    45. sentence_test = input()
    46. ori_dict2 = {}
    47. sentence_ori_temp = reform(sentence_ori)
    48. ori_list = segmentation(sentence_ori_temp, ori_dict)
    49. sentence_tes_temp = reform(sentence_test)
    50. tes_list = segmentation(sentence_tes_temp, None)
    51. count_list = compareList(ori_list, tes_list)
    52. p = probability(tes_list, ori_dict, count_list)
    53. print(p)

    第2关:数据平滑

    任务描述

    本关任务:实现二元语言模型的数据平滑,并利用平滑后的数据计算句子概率。

    相关知识

    为了完成本关任务,你需要掌握:1.模型平滑化。2.good-turning平滑。

    模型平滑

    在使用语言模型直接计算某个句子出现的概率时,可能会由于某个单词或单词对出现的概率为0而导致整个句子出现的概率为0。 例如下面这个场景:

    例子

    在上面的场景中,由于部分单词对出现的概率为0,导致最终两句话出现的概率均为0。但实际上,s1=“今天没有训练营”比s2=“今天训练营没有”更符合语法习惯,我们也更希望计算出来的P(s1)大于P(s2)。 一般来说,语言模型的平滑处理可分为以下三类:

    • Discounting(折扣):通过给概率不为0的项打折扣,来提高概率为0的项的概率;
    • Interpolation(插值):在使用N-gram模型计算某一项的概率时,同时结合低阶的模型所计算出的概率;
    • Back‐off:approximate counts of unobserved N‐gram based on the proportion of back‐off events (e.g., N‐1 gram)。

    这里我们主要介绍与使用Discounting中的good-turning平滑方法。

    good-turning平滑

    Good-Turing技术是在1953年由古德(I.J.Good)引用图灵(Turing)的方法而提出来的,其基本思想是:用观察计数较高的N元语法数重新估计概率量的大小,并把它指派给那些具有零计数或者较低计数的N元语法。涉及的符号含义为:
    c:某个N元语法出现的频数。
    Nc:出现次数为c的 N-gram 词组的个数,是频数的频数

    ,

    c*:Good-Turing平滑计数

    ,

    设N为测试元组集合中元组的数目,则有如下公式:

    ,

    通过新频数可计算出经过good-turing平滑后的元组概率,公式如下:

    ,

    编程要求

    根据提示,在右侧编辑器补充代码,编写平滑函数,计算句子的概率

    测试说明

    平台会对你编写的代码进行测试:

    语料库:

    1. 研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。

    测试输入:

    1. 他是研究物理的

    预期输出:

    1. 5.6888888888888895e-05

    1. import jieba
    2. #语料句子
    3. sentence_ori="研究生物很有意思。他大学时代是研究生物的。生物专业是他的首选目标。他是研究生。"
    4. #测试句子
    5. sentence_test=input()
    6. #任务:编写平滑函数完成数据平滑,利用平滑数据完成对2-gram模型的建立,计算测试句子概率并输出结果
    7. # ********** Begin *********#
    8. def gt(N, c):
    9. if c+1 not in N:
    10. cx = c+1
    11. else:
    12. cx = (c+1) * N[c+1]/N[c]
    13. return cx
    14. jieba.setLogLevel(jieba.logging.INFO)
    15. sentence_ori = sentence_ori[:-1]
    16. words = jieba.lcut(sentence_ori)
    17. words.insert(0, "BOS")
    18. words.append("EOS")
    19. i = 0
    20. lengh = len(words)
    21. while i < lengh:
    22. if words[i] == "。":
    23. words[i] = "BOS"
    24. words.insert(i, "EOS")
    25. i += 1
    26. lengh += 1
    27. i += 1
    28. phrases = []
    29. for i in range(len(words)-1):
    30. phrases.append(words[i]+words[i+1])
    31. phrasedict = {}
    32. for phrase in phrases:
    33. if phrase not in phrasedict:
    34. phrasedict[phrase] = 1
    35. else:
    36. phrasedict[phrase] += 1
    37. words_test = jieba.lcut(sentence_test)
    38. words_test.insert(0, "BOS")
    39. words_test.append("EOS")
    40. phrases_test = []
    41. for i in range(len(words_test)-1):
    42. phrases_test.append(words_test[i]+words_test[i+1])
    43. pdict = {}
    44. for phrase in phrases_test:
    45. if phrase not in phrasedict:
    46. pdict[phrase] = 0
    47. else:
    48. pdict[phrase] = phrasedict[phrase]
    49. N = {}
    50. for i in pdict:
    51. if pdict[i] not in N:
    52. N[pdict[i]] = 1
    53. else:
    54. N[pdict[i]] += 1
    55. N[0] += 1
    56. Nnum = 0
    57. for i in N:
    58. Nnum += i*N[i]
    59. p = 1
    60. for phrase in phrases_test:
    61. c = pdict[phrase]
    62. cx = gt(N, c)
    63. p *= cx/Nnum
    64. print(p)

     

  • 相关阅读:
    vue @click点击事件不生效
    JNPF低代码开发
    他来了他来了,.net开源智能家居之苹果HomeKit的c#原生sdk【Homekit.Net】1.0.0发布,快来打造你的私人智能家居吧
    SpringBoot3.1.5对应新版本SpringCloud开发(1)-Eureka注册中心
    mac电脑重装系统操作步骤
    JMM对数据竞争的定义
    2022年湖北特种作业操作证应急管理厅怎么报考?甘建二
    mysql的约束和表关系
    java —— 打印流
    研发过程中的文档管理与工具
  • 原文地址:https://blog.csdn.net/cfy2401926342/article/details/137906454