卢镇seo网站优化排名,设计app的软件有哪些,郑州抖音推广,手工做环保衣的网站工程报告 目录 1 研究背景 4 2 工程目标 7 2.1 工程一 7 2.2 工程二 7 2.3 工程三 7 2.4 工程四 7 3 实验环境与工具 7 4 模型方法 8 4.1 n-gram模型 8 4.2 模型的平滑 9 4.2.1 Add-one 9 4.2.2 Add-k 9 4.2.3 Backoff 10 4.2.4 Interpolation 10 4.2.5 Absolute discounting 1…工程报告 目录 1 研究背景 4 2 工程目标 7 2.1 工程一 7 2.2 工程二 7 2.3 工程三 7 2.4 工程四 7 3 实验环境与工具 7 4 模型方法 8 4.1 n-gram模型 8 4.2 模型的平滑 9 4.2.1 Add-one 9 4.2.2 Add-k 9 4.2.3 Backoff 10 4.2.4 Interpolation 10 4.2.5 Absolute discounting 10 4.2.6 Kneser-Ney 10 4.2.7 Modified Kneser-ney 11 4.3 最大匹配法 11 4.3.1 最大前向匹配 11 4.3.2 最大后向匹配 11 4.3.3 基本原则 12 4.4 隐马尔科夫模型 12 4.5 维特比算法 12 5 系统设计 13 5.1 宋词词频统计 13 5.2 宋词自动生成 14 5.3 中文词频统计 16 5.4 中文词法分析系统 18 6 系统演示 23 7 课程学习心得 25 参考文献 25 附录A:源代码 25
1 研究背景
自然语言理解研究用电子计算机模拟人的语言交际过程使计算机能理解和运用人类社会的自然语言如汉语、英语等实现人机之间的自然语言通信以代替人的部分脑力劳动包括查询资料、解答问题、摘录文献、汇编资料以及一切有关自然语言信息的加工处理。这在当前新技术革命的浪潮中占有十分重要的地位。 自然语言处理的发展历程是一个艰辛且充满机遇的过程从提出至今已有70多年的历史但是现在仍处于期望膨胀期且被评为了AI未来十年重点发展方向。在其发展过程中可分为三个阶段第一个阶段为符号主义与经验主义占主流的阶段第二个阶段为理性主义与统计主义占主流的阶段第三个阶段为连接主义占主流的阶段。在第三阶段连接主义时可以从最初的神经元数学模型(MP模型开始到1960至1970年代的连接主义如脑模型再到Rumelhart等在1986年建立的反向传播算法[1]最终过渡到近几年的循环神经网络(Recurrent Neural Network,RNN)、长短期记忆网络(Long Short-Term Memory,LSTM)、词嵌入(word embedding)、注意力模型(Attention Model,AM)等以时间为主线理论与技术的发展为脉络进行介绍与分析。自然语言处理发展历程可从以下几个维度进行研究。 1.1 从不同学派的理论与技术看待自然语言处理发展历程 自然语言处理高度融合了数学计算机等学科研究方向中也包含了神经科学生物学心理学等。在自然语言处理发展的历史中我们会看到不同学派之间的碰撞。正如哲学中的经验主义与理性主义一样自然语言处理领域中的经验主义统计主义更看重的是证据即所有理论和假设都必须被实验来检验。所以我们可以发现经验主义的方法都是统计的整个语料库中的概率以此作为经验来验证我们的后续任务。而自然语言处理领域中的理性主义符号主义也如哲学中的理性主义认为大部分的知识是来自感觉上的独立思考。就像正则表达式只提取我们需要的内容而不会关心这个词在句子中是否是一个独立的个体。 在多个学派各自探索与研究的过程中在初期时代是孤立的。可是随着学者们的不断前进呈现出了高度综合化的趋势。自然语言处理在21世纪迎来发展的高潮正是从图像与语音领域得到了启发结合了深度学习才得到的成果。而这个高潮时代也离不开其他领域发展所带来的贡献如果没有计算机科学、脑神经科学与认知科学不断发展而带来神经网络的高潮[2]也不会有连接主义的出现。随着学者们对自然语言处理研究的深入不同学派之间也产生了融合。 1.2 从单一技术的发展看待自然语言处理发展历程 恩格斯的否定之否定规律揭示了事物发展的方向和道路[3]。在自然语言处理知识体系中学者们对词嵌入技术的研究过程是一个不断螺旋上升的过程。学者们提出了一个新的词向量构建技术后人在研究的过程中会发现其的不足并加之完善。这样的过程伴随着词嵌入这项技术的发展。虽然在研究的过程中出现了许多问题甚至谬误但技术发展并未停滞在学者们一次又一次地发现了不足后加之完善达到了更好的境地。可见词嵌入技术的发展历程是螺旋式、曲折式前进的过程。以否定之否定规律来看词嵌入技术的发展历程可看成是技术内部矛盾引起的自我否定内部矛盾转化最终解决矛盾的过程[4]。而从整个词嵌入技术的发展过程来看我们也可以推测出整个自然语言处理领域的发展是类似的情况都是在前人工作中发现不足并进行改正不断完善理论的一个过程。在研究该领域的过程中我们要从其历史进行科学的解读针对出现的新问题发现过去理论的不足改正这些错误并不断完善这个领域的理论。 1.3 从系统思维看待自然语言处理发展历程 系统思维是指将事物看成系统进行分析与处理[5]。在整个自然语言处理的过程中自然语言处理可看作为一个系统它是人工智能系统的一个子系统。系统理论与方法对自然语言处理技术的发展起重要的指导和促进作用。 系统理论着重从全局和整体两方面分析问题注重事物之间的复杂联系而不单方面地分析问题[6]。就像在自然语言处理的研究中现阶段的工作都是基于文档、基于句子甚至是基于词语的虽然我们能够将其看作为一个系统但是人类在表达一句话的时候有可能会暗含许多信息比如输入“520快乐”给计算机计算机只能识别出一串数字“520”和一个词“快乐”却不能够理解“520”暗指网络情人节。这就表明了尽管现在自然语言处理正在蓬勃发展但是却有一定的缺陷。近年来知识工程学科的研究就正在致力于解决计算机没有外部知识这一问题[7]。从这个方面来说尽管现在对自然语言处理系统化的研究已经有了显著成果但是依旧需要学者们站在一个更为宏观的角度来系统化看待这个问题。 1.4 从数学方法看待自然语言处理发展历程 数学是辩证的辅助手段和表达方式[8]。在学者研究自然语言处理的过程中特别是统计主义学派与连接主义学派及其融合学派通过发现自然语言的内在规律对其进行数学建模将其用数学公式形式化表达出来。正是由于数学作为基石自然语言处理才能够稳步发展。计算机处理文字是一件复杂的事正是由于词嵌入技术将文字映射到向量空间才能够降低计算机运行的成本。在隐含马尔科夫模型中通过双随机过程能够实现为词语打标签的工作。数学无处不在在发展过程中扮演举足轻重的作用正是由学者将发现的规律进行简化并形式化表达为数学公式才能够有层出不穷的新技术诞生。 1.5 从联系与发展看待自然语言处理发展历程 自然语言处理的发展历史上离不开辩证法中联系与发展的两大特征。如语言模型[9]正是学者们发现了相邻的词语之间存在关联关系并对这种内在规律建模才有了相应的研究。同时正因为其他学科的学者们在自然界等发现了相应的规律才有学者能够将其引入到自然语言处理中。注意力机制也正是学者们研究了人类的注意力机制发现了其中的客观性与普遍性才能够通过数学对其建模而引入到计算机科学中接着才能够应用到自然语言处理领域。从以上两个例子我们可以看出学者们不仅对一句话中的词语之间的关联关系进行了研究还将自然界中的客观现象引入到了自然语言处理中这也反映了辩证法联系的思想。 从自然语言处理技术的发展路线我们可以发现这种发展是具有普遍性的并没有因为过程的曲折而致使技术停滞不前。且学者们通过分析总结前人的不足并加之完善这体现出了发展的实质事物的前进与上升。尽管事物的前进方向是光明的但是学者们用了几年甚至几十年才慢慢完善该学科也就体现出了事物发展道路的曲折性。最后我们可以发现如果不是之前学者们从one-hot编码到语言模型的提出也不会有Word2Vec这种模型的创建。Word2Vec正是吸收了前面词嵌入技术的精华而提炼出的一个全新技术这正印证了辩证法发展性中量变引起质变的特性。 1.6 从学术前沿看待自然语言处理发展历程 自然语言处理中多学科交叉融合的优势越来越明显在研究过程中会有更多的新思想、新技术融合到自然语言处理自然语言处理的应用领域越来越广泛。自然语言处理的学术前沿代表当前学术界或工业界需解决的理论或技术问题教学过程中适当地将学术前沿理论融入自然语言处理发展历程中进行教学增强学生自主学习动力激发学生的科研兴趣。比如计算机在处理文本数据时它并不能很好地识别出一个句子中包含的外部知识和真实情感我们需要研究在知识指导下的自然语言处理技术建立知识获取、知识产生、知识表达等与自然语言处理的方法与技术使计算机能够智能认知和理解自然语言。同时其他学科所产生的新理论、新技术为自然语言处理提供了良好的基石可以引导学生尝试借鉴这些新理论与新技术构建出新模型、新技术推动自然语言处理的新发展。
2 工程目标
2.1 工程一
宋词词频统计 语料库: ci.txt 要求: 编程序, 输入ci, 自动分析统计ci.txt, 统计宋词的单字词, 双字词等。统计后输出的是单字词和双字词的词典文件。文件中包括相应的词和频度次数。
2.2 工程二
宋词自动生成 语料库:ci.txt 要求: 输入词牌,基于宋词的词典和宋词的词牌,可以随机或者按照语言模型,自动生成宋词。设计相应的Ui或者Web界面。
2.3 工程三
中文词频统计 语料库:1998-01-2003版-带音.txt 要求:输入txt文件,统计1元模型和2元模型,输出单词和词频文件,双词和词频文件。设计相应的接口,能够快速载入文件,并检索单词和双词。
2.4 工程四
中文词法分析系统 语料库:1998-01-2003版-带音.txt 要求:根据构建的单词词典和双词词典,用n-gram模型,或者前向最长匹配,或者后向最长匹配等算法,鼓励用更复杂一些的方法来进行,包括隐马尔科夫模型和条件随机场模型。
3 实验环境与工具
编辑工具Visual Studio Code 编译工具python 3.9.7 界面工具PyQt5 designer 用到的库re; collections; random; PyQt5 5.15.4; 版本工具Git 操作系统Windows10
4 模型方法
4.1 n-gram模型
N-gram模型属于概率语言模型其要解决的问题其实很简单那就是从是否符合自然语言的角度评估一个句子的质量。在这个问题中句子W被建模成词的排列 W w1, w2,…wn所谓质量就就是句子出现的概率也即该排列出现的联合概率
但是要计算概率要么通过概率密度函数要么用统计概率近似。自然语言的概率密度函数我们肯定是无法知道了那么就要用统计概率所以必须要有一个自然语言的样本库里面包含了大量的自然语言的句子实例在N-gram模型中用到的便是语料库。 那么怎么通过语料库来计算句子出现的概率呢这就涉及到马尔科夫链的假设即当前词出现的概率 P (wi)仅与前N-1个词有关这里的N就对应N-gram里面的N。所以N-gram模型的构建只需要计算出所有的N以内的条件概率即可
例如常用的当N3时句子W出现概率就简化为
可以看到当N增大时需要计算的概率将会大大增多其计算量几乎是与N成指数关系的增长因为每多考虑一阶每个词都大约需要多考虑M个“新的概率”。谷歌当初使用的N4的语言模型需要500台以上的服务器进行存储这是不可想象的。 而且即使N取的再大也无法完全覆盖后文对前文的依赖关系语言的上下文联系可以跨度很大而N的增长对计算量增大带来的压力完全无法满足这种大跨度的上下文联系。 N-gram模型是基于对语料库的统计来进行训练的举例来说对于Bigram模型我们要计算 p (like∣you)那么公式为
其中 C(wi)表示语料库中单词wi出现的次数。 仍然以Bigram模型为例我们的目标函数是:
由于又涉及到多个概率连乘问题所以我们映射到对数空间即
我们的任务是最大化这个对数似然因此这种参数估计的方式就叫做MLE(Maximum Log Likelihood)
4.2 模型的平滑
4.2.1 Add-one
Add-one 是最简单、最直观的一种平滑算法既然希望没有出现过的N-gram的概率不再是0那就直接规定在训练时任何一个N-gram在训练预料至少出现一次即规定没有出现的在语料中也出现一次因此Countnew(n-gram) countold(n-gram)1; 于是对于n-gram的模型而言假设V是所有可能的不同的N-gram的类型个数那么根据贝叶斯公式有
然这里的n-gram的可以相应的改成uingram和bigram表达式并不影响。其中Cx为x在训练中出现的次数wi为给定的训练数据中第i个单词。 这样一来训练语料库中出现的n-gram的概率不再为0而是一个大于0的较小的概率值Add-one平滑算法确实解决了我们的问题但是显然它也并不完美由于训练语料中未出现的n-gram数量太多平滑后所有未出现的占据了整个概率分布的一个很大的比例因此在自然语言处理中Add-one给语料库中没有出现的n-gram分配了太多的概率空间。此外所有没有出现的概率相等是不是合理这也是需要考虑的。
4.2.2 Add-k
由Add-one衍生出来的另一种算法就是Add-k既然我们认为加1有点过了那么我们可以选择一个小于1的正数k概率计算公式就可以变成如下表达式
它的效果通常会比Add-one好但是依旧没有办法解决问题至少在实践中k必须认为的给定而这个值到底多少该取多少都没有办法确定。
4.2.3 Backoff
回退模型思路实际上是当使用Trigram的时候如果Counttrigram满足条件就使用否则使用Bigram再不然就使用Unigram.公式如下其中da和k分别为参数。k一般选择为0但是也可以选其它的值。
4.2.4 Interpolation
Interpolation插值法和回退法的思想非常相似设想对于一个trigram的模型我们要统计语料库中“”“I like you”出现的次数结果发现它没有出现则计数为0在回退策略中们将会试着用低阶的gram来进行替代也就是用“like you”出现的次数来替代。在使用插值的时候我们把不同阶层的n-gram的模型线性叠加组合起来之后再使用简单的如trigram的模型按照如下的方式进行叠加
4.2.5 Absolute discounting
插值法使用的参数实际上没有特定的选择如果将lamda参数根据上下文进行选择的话就会演变成Absolute discounting。对于这个算法的基本想法是有钱的每个人交固定的税D建立一个基金没有钱的根据自己的父辈有多少钱分这个基金。比如对于bigram的模型来说有如下公式。
4.2.6 Kneser-Ney
这种算法是目前一种标准的而且是非常先进的平滑算法它其实相当于前面讲过的几种算法的综合。它的思想实际上是有钱的人每个人交一个固定的税D大家一起建立一个基金没有钱的呢根据自己的的父辈的“交际的广泛”的程度来分了这个基金。这里交际的广泛实际上是指它父辈会有多少种不同的类型类型越多这说明越好。其定义式为
其中maxc(X)-D,0的意思是要保证最后的计数在减去一个D后不会变成一个负数D一般大于0小于1。这个公式递归的进行直到对于Unigram的时候停止。而lamda是一个正则化的常量用于分配之前的概率值也就是从高频词汇中减去的准备分配给哪些未出现的低频词的概率值分基金池里面的基金。
4.2.7 Modified Kneser-ney
这一种方法是上一种方法的改进版而且也是现在最优的方法。上一个方法每一个有钱的人都交一个固定的锐这个必然会出现问题就像国家收税一样你有100万和你有1个亿交税的量肯定不一样这样才是比较合理的因此将上一种方法改进就是有钱的每个人根据自己的收入不同交不同的税D建立一个基金没有钱的根据自己的父辈交际的广泛程度来分配基金。
4.3 最大匹配法
4.3.1 最大前向匹配
设MaxLen表示最大词长D为分词词典 (1) 从待切分语料中按正向取长度为MaxLen的字串str,令LenMaxLen; (2) 把str与D中的词从左往右相匹配; (3) 若匹配成功则认为该字串为词指向待切分语料的指针向前移Len个汉字返回到1; (4) 若不成功如果Len1则将Len减1从待切分语料中 取长度为Len的字串str,返回到2。否则得到长度为2的单字词指向待切分语料的指针向前移1个汉字返回1。
4.3.2 最大后向匹配
设MaxLen表示最大词长D为分词词典 (1) 从待切分语料中按正向取长度为MaxLen的字串str,令LenMaxLen; (2) 把str与D中的词从右往左相匹配;
(3) 若匹配成功则认为该字串为词指向待切分语料的指针向后移Len个汉字返回到1; (4) 若不成功如果Len1则将Len减1从待切分语料中取长度为Len的字串str,返回到2。否则得到长度为2的单字词指向待切分语料的指针向后移1个汉字返回1。
4.3.3 基本原则
颗粒度越大越好用于进行语义分析的文本分词要求分词结果的颗粒度越大即单词的字数越多所能表示的含义越确切。 切分结果中非词典词越少越好单字字典词数越少越好这里的“非词典词”就是不包含在词典中的单字而“单字字典词”指的是可以独立运用的单字。
4.4 隐马尔科夫模型
存在一类重要的随机过程如果一个系统有N个状态S1,S2,…,SN,随着时间的推移该系统从某一状态转移到另一状态。如果用q 表示系统在时间t的状态变量那么t时刻的状态取值为S(1jN) 的概率取决于前t-1 个时刻(1,2,…,t-1)的状态该概率为 假设一如果在特定情况下系统在时间t 的状态只与其在时间t-1 的状态相关则该系统构成一个离散的一阶马尔可夫链
假设二假设二如果只考虑公式(14)独立于时间t的随机过程即所谓的不动性假设状态与时间无关那么
该随机过程称为马尔可夫模型。
4.5 维特比算法
(1) 从点S出发对于第一个状态X的各个节点不妨假定有n个计算出S到它们的距离d(S,X)其中X代表任意状态1的节点。因为只有一步所以这些距离都是S到它们各自的最短距离。 (2) 对于第二个状态X的所有节点要计算出从S到它们的最短距离。对于特点的节点X从S到它的路径可以经过状态1的n中任何一个节点X对应的路径长度就是d(S,X) d(S,X) d(X,X)。由于j有n种可能性我们要一一计算找出最小值。 这样对于第二个状态的每个节点需要n次乘法计算。假定这个状态有n个节点把S这些节点的距离都算一遍就有O(n·n)次计算。 (3) 接下来类似地按照上述方法从第二个状态走到第三个状态一直走到最后一个状态就得到了整个网格从头到尾的最短路径。每一步计算的复杂度都和相邻两个状态S和S各自的节点数目nn的乘积成正比即O(n·n) (4) 假设这个隐含马尔可夫链中节点最多的状态有D个节点也就是说整个网格的宽度为D那么任何一步的复杂度不超过O(D)由于网格长度是N所以整个维特比算法的复杂度是O(N·D)。
5 系统设计
5.1 宋词词频统计
本工程模块划分
函数名称函数输入函数输出get_one_word()宋词语料库单字词词典文件get_two_word()宋词语料库双字词词典文件Main()程序开始程序结束
表 1 工程一模块划分 对于宋词词频的统计主要是对单字词的统计和双字词的统计。在宋词词频统计的系统当中利用两个词典word_dictword_dict2分别用于存储单字词的词频和双字词的词频信息。 图 1 统计单字词代码 单字词基本思想对Ci.txt逐行读取每一个字判断读取的每一个字的utf-8编码是不是在汉字编码值范围内若在则为单字词将其放入列表。读取完毕后用字典对列表中的所有字进行字数统计若字典中已经存在该字则直接将字典中该字对应的键值加一否则在字典中新増一个键键为该字键值为1。统计完毕后将其排序写入单字词.txt中。其中可设置一个特殊符号字典来去掉特殊符号字典如下 exclude_str 。、 【 】 《 》 - * — “ ” … ‘\n’ 图 2 统计双字词代码 双字词基本思想双字词的统计过程和单字词类似因为统计的是双字词所以判断条件变成了当前读取的字及其下一个字是否均为汉字。对Ci.txt逐行读取每一个字判断读取的每一个字的utf-8编码及其下一个字的utf-8编码是不是都在汉字编码值范围内若都在则为双字词将其放入列表。读取完毕后用字典对列表中的所有词进行词数统计若字典中已经存在该词则直接将字典中该词对应的键值加一否则在字典中新増一个键键为该词键值为1。统计完毕后将字典按字频排序后写入双字词.txt中。其中汉字的utf-8编码范围是’\u4e00’到’\u9fa5’。此处也可以用正则表达式去掉。 最后将统计好的字典按照键值对的大小排列由大到小写入到文件中去。
5.2 宋词自动生成
本工程模块划分
函数名称函数输入函数输出main()程序开始程序结束Ui_MainWindow()无初始化一个界面对象Mywindow()在界面上输入词牌名将生成的词显示在界面create_Songci()词牌名生成词
表 2 工程二模块划分 用PyQt5简单的设计了一个界面。 图 3 PyQt5设计的界面 程序第一次运行先将工程一中的保存好的“单字词.txt”和“双字词.txt”加载到内存中。然后再将宋词语料库加载到内存中。因为宋词的固定格式是根据词牌名来的所以当用户输入词牌名时需要在语料库中寻找是否有对应的词牌名没有则随机生成一个格式的词。若有相应的词牌名程序会根据系统已有的词的格式加载到一个列表中(格式如下 [3, ‘,’, 5, ‘。’, 3, ‘,’, 5, ‘。’],意识是先随机三个字或词然后逗号五个词句号等等。寻找的词过程就是在工程一保存的文件接口中随机选择词。 起初我设计的代码是这样的: 图 4 第一次设计的代码 其中为了满足格式的要求用了大量的if-else语句来符合题意不适合读也不适合写后来优化成了以下的方法 图 5 第二次设计的代码 这样设计代码清晰明了没事随机选择一个数数的范围是1和2,若当前的值减去选择的随机数大于等于零说明可以填一个词那就填词否则再次选择随机数。
5.3 中文词频统计
本工程模块划分
函数名称函数输入函数输出Main()程序开始程序结束get_one_word()1998-01-2003版-带音单词和词频文件get_two_word()1998-01-2003版-带音双词和词频文件
表 3 工程三模块划分 首先读取语料库:1998-01-2003版-带音.txt用正则表达式将语料库中的词性和括号去掉 图 6 用正则表达式去掉词性和括号 单词并不是一个字的意思而是一个词或者一个字分割之后不能表达原意的词即分割失意的词。对得到的text列表逐行读取把不是和的词元素加入到单词表把相邻的两个词组成双词放入双词表中。 图 7 统计单词和双词 对单双字词统计词频完后进行对一元\二元模型.txt.文件进行输出填充文件。下一步则是实验四的内容利用最大向前算法对句子进行切分在此步骤前要对后续输入的句子进行分句处理目的是以免效率过低带来麻烦。 设计思路是首先在句首和句尾都添加一个索引然后尾部的索引逐步往前移同时判断索引间是否为文件中的单字词直到索引相遇如果词出现在了词典里即索引间内容是一个词则将其当成一个单字词若这个词没有出现在词典里则把这个字单独分开。随后首部索引将定位在我们已经划分过的词后面尾部索引位置依旧是句尾按上述操作循环进行直到所有的字都被我们划入了字词块中。 最后程序输入要查询的词在创建的接口中查询若返回的个数不为0则语料库中存在该词输出该词的词性单词或双词。
5.4 中文词法分析系统
本工程模块划分
函数名称函数输入函数输出Main()一个待分析的句子两种分析结果Get_max_forword_split_sentence()一个待分析的句子最大前向概率划分的句子Get_max_backword_split_sentence()一个待分析的句子最大后向概率划分的句子
表 4 工程四模块划分 程序首先输入待分析的句子然后将句子传递参数给分析的两个函数进行句子的划分 最大前向匹配 设MaxLen表示最大词长D为分词词典 (1) 从待切分语料中按正向取长度为MaxLen的字串str,令LenMaxLen; (2) 把str与D中的词从左往右相匹配; (3) 若匹配成功则认为该字串为词指向待切分语料的指针向前移Len个汉字返回到1; (4) 若不成功如果Len1则将Len减1从待切分语料中 取长度为Len的字串str,返回到2。否则得到长度为2的单字词指向待切分语料的指针向前移1个汉字返回1。 图 8 最大前向匹配流程图 图 9 最大前向匹配代码实现 最大后向匹配 设MaxLen表示最大词长D为分词词典 (1) 从待切分语料中按正向取长度为MaxLen的字串str,令LenMaxLen; (2) 把str与D中的词从右往左相匹配; (3) 若匹配成功则认为该字串为词指向待切分语料的指针向后移Len个汉字返回到1; (4) 若不成功如果Len1则将Len减1从待切分语料中取长度为Len的字串str,返回到2。否则得到长度为2的单字词指向待切分语料的指针向后移1个汉字返回1。 逆向最大匹配法从被处理文档的末端开始匹配扫描每次取最末端的m个字符(m为词典中最长词数作为匹配字段若匹配失败则去掉匹配字段最前面的一个字继续匹配。相应地它使用的分词词典是逆序词典其中的每个词条都将按逆序方式存放。在实际处理时先将文档进行倒排处理生成逆序文档。然后根据逆序词典对逆序文档用正向最大匹配法处理即可。由于汉语中偏正结构较多若从后向前匹配可以适当提高精确度。所以逆向最大匹配法比正向最大匹配法的误差要小 图 10 最大后向匹配流程图 图 11 最大后向匹配代码实现 双向最大匹配 将正向最大匹配法得到的分词结果和逆向最大匹配法得到的结果进行比较然后按照最大匹配原则选取词数切分最少的作为结果。据研究表明对于中文中90.0%左右的句子正向最大匹配和逆向最大匹配的切分结果完全重合且正确只有大概9.0%的句子采用两种切分方法得到的结果不一样但其中必有一个是正确的(歧义检测成功),只有不到1.0%的句子或者正向最大匹配和逆向最大匹配的切分结果虽重合却都是错的或者正向最大匹配和逆向最大匹配的切分结果不同但两个都不对(歧义检测失败)。这正是双向最大匹配法在实用中文信息处理系统中得以广泛使用的原因所在。双向最大匹配的规则如下所示 如果正反向分词结果词数不同则取分词数量较少的那个结果如果分词结果词数相同则 分词结果相同就说明没有歧义可返回任意一个结果。分词结果不同返回其中单字较少的那个。实现代码如下 图 12 双向匹配代码实现
6 系统演示
运行工程一中的main.py,输出结果在同路径下的“单字词.txt”和“双字词.txt” 图 13 工程一结果截图
运行工程二中的main.py,在文本框中输入词牌名系统自动在界面输出词的内容如下图所示 图 14 工程二结果截图 运行工程三中的main.py, 系统单词语料库.txt文件,自动统计1元模型和2元模型,输出单词和词频文件,双词和词频文件。并设计相应的接口文件,能够快速载入文件,并检索单词和双词。输入词语返回它是单字词还是双字词并返回词频。 图 15 工程三结果截图 运行工程四中的main.py, 根据工程三中构建的单词词典和双词词典文件接口, 程序输入待划分的句子系统自动利用用前向最长匹配,后向最长匹配和双向最长匹配,来划分语句。如下所示 图 16工程四结果截图
7 课程学习心得
谷雨老师是我们自然语言处理课的老师他上课非常生动有趣我记忆最深刻的是有一堂课讲古诗如何翻译成英语举了很多有名的句子很有趣。我清楚的记得有 “浮世三千吾爱有三。日月与卿。日为朝月为暮卿为朝朝暮暮。” 课程的这四个实验都很有意思自动生成宋词自动断句这些都让第一次接触自然语言理解的我倍感惊奇。通过这几个实验使我更加深入的了解了自然语言这门课程。这几个实验的内容都很吸引人并且这几个实验当中都用到了很多上课讲过的算法和思想在做实验的过程当中更加深刻地体会了这些算法的思想和如何将他们转换成代码的形式呈现出来。通过实本次实验我学习到了很多的东西。 通过对本门课的学习我对NLP相关内容有了了解和认知。感受到了各类日常行为带来的信息量同时也通过实验自己进行了操作对统计规划方面打下基础。知道了这一领域的研究涉及自然语言即人们日常使用的语言所以它与语言学的研究有着密切的联系。希望在以后的学习路程中借助学习本门课打下的基础可以更熟练地探寻各类与语言学相关的联系可以更好地发挥所学的知识同时也希望在以后的教学里可以更多地提供让我们亲自动手进行实验地步骤增加书本知识与实际操作地结合时间以达到更好的教学成果。
参考文献
中国互联网信息中心.第48次中国互联网发展状况统计报告[R].中国:CNNIC2021.陈艳平.自然语言处理课程教学探索和实践[J].科教文汇(上旬刊) ,2020(12):135-136.计算语言学中的语言模型[J]. 冯志伟,丁晓梅. 外语电化教学. 2021(06)生成词向量的三种方法[J].冯志伟.外语电化教学.2021(01)Efficient Estimation of Word Representations in Vector Space[J].Tomas Mikolov,Kai Chen 0010,Greg Corrado,Jeffrey Dean.CoRR .2013自然语言处理中的预训练范式[J]. 冯志伟,李颖. 外语研究. 2021(01)神经网络、深度学习与自然语言处理[J].冯志伟.上海师范大学学报(哲学社会科学版).2021(02)深度学习在自然语言处理领域的研究进展[J]. 江洋洋,金伯,张宝昌. 计算机工程与应用. 2021(22)A broad-coverage challenge corpus for sentence understanding through inference. Williams A,Nangia N,Bowman S R. . 2017
附录A:源代码
实验一 Main.py
Author: Martin
Date: 2022-10-13 19:05:43宋词词频统计
语料库: ci.txt
要求: 编程序, 输入ci, 自动分析统计ci.txt, 统计宋词的单字词, 双字词等。
统计后输出的是单字词和双字词的词典文件。文件中包括相应的词和频度次数。file_path_in rD:\a表格\课件\大三上\自然语言处理\实验\Ci.txt
file_path_out_1 rD:\a表格\课件\大三上\自然语言处理\实验\实验一\单字词.txt
file_path_out_2 rD:\a表格\课件\大三上\自然语言处理\实验\实验一\双字词.txt
exclude_str 。、 【 】 《 》 - * — “ ” … \ndef get_one_word():写入文件 file_path_out_1word_dict {} #{word:num}ret_word_dict [] #[(word,num),(word,num)]# 读文件with open(file_path_in,r,encodingutf-8) as fp:# 字典统计赋值for line in fp:line line.strip()if len(line) 10:continuefor char in line:if char not in exclude_str:# 用字典统计每个字出现的个数和频率word_dict[char] word_dict.get(char,0)1# 对字典排序变成[(word,num),(word,num)]ret_word_dict sorted(word_dict.items(),keylambda x : x[1],reverseTrue)# print(ret_word_dict)with open(file_path_out_1,w,encodingutf-8) as fp:for item in ret_word_dict:fp.write(item[0])fp.write(\t)fp.write(str(item[1]))fp.write(\n)def get_two_word():写入文件 file_path_out_2word_dict {} #{words:num}ret_word_dict [] #[(words,num),(words,num)]# 读文件with open(file_path_in,r,encodingutf-8) as fp:# 字典统计赋值for line in fp:line line.strip()if len(line) 10:continuefor i in range(len(line)-1):# 确保是汉字编码if \u4e00line[i]\u9fa5 and \u4e00line[i1]\u9fa5:# 用字典统计每个字出现的个数和频率word_dict[line[i]line[i1]] word_dict.get(line[i]line[i1],0)1# 对字典排序变成[(word,num),(word,num)]ret_word_dict sorted(word_dict.items(),keylambda x : x[1],reverseTrue)# print(ret_word_dict)with open(file_path_out_2,w,encodingutf-8) as fp:for item in ret_word_dict:fp.write(item[0])fp.write(\t)fp.write(str(item[1]))fp.write(\n)def main():get_one_word()get_two_word()
if __name__ __main__:main()实验二 Ui_test2.py Author: Martin
Date: 2022-10-17 20:58:36# -*- coding: utf-8 -*-# Form implementation generated from reading ui file d:\a表格\课件\大三上\自然语言处理\实验\实验二\test2.ui
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName(2020210593李海跃)MainWindow.resize(683, 383)self.centralwidget QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName(centralwidget)self.pushButton QtWidgets.QPushButton(self.centralwidget)self.pushButton.setGeometry(QtCore.QRect(580, 40, 75, 23))self.pushButton.setObjectName(pushButton)self.label QtWidgets.QLabel(self.centralwidget)self.label.setGeometry(QtCore.QRect(240, 35, 171, 21))self.label.setObjectName(label)self.textEdit_1 QtWidgets.QTextEdit(self.centralwidget)self.textEdit_1.setGeometry(QtCore.QRect(270, 70, 161, 31))self.textEdit_1.setObjectName(textEdit_1)self.textEdit_2 QtWidgets.QTextEdit(self.centralwidget)self.textEdit_2.setGeometry(QtCore.QRect(110, 130, 481, 141))self.textEdit_2.setObjectName(textEdit_2)MainWindow.setCentralWidget(self.centralwidget)self.menubar QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 683, 26))self.menubar.setObjectName(menubar)self.menu2020210593 QtWidgets.QMenu(self.menubar)self.menu2020210593.setObjectName(menu2020210593)MainWindow.setMenuBar(self.menubar)self.statusbar QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName(statusbar)MainWindow.setStatusBar(self.statusbar)self.menubar.addAction(self.menu2020210593.menuAction())self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate(MainWindow, MainWindow))self.pushButton.setText(_translate(MainWindow, Create!))self.label.setText(_translate(MainWindow, 请输入词牌名))self.menu2020210593.setTitle(_translate(MainWindow, 2020210593))main.py Author: Martin
Date: 2022-10-17 20:09:59宋词自动生成
语料库:ci.txt
要求: 输入词牌,基于宋词的词典和宋词的词牌,可以随机或者按照语言模型,自动生成宋词。设计相应的Ui或者Web界面。
import random
from Ui_test2 import Ui_MainWindow
import sys
from PyQt5 import QtWidgets
import re# 主界面
class Mywindow(QtWidgets.QMainWindow):def __init__(self):QtWidgets.QMainWindow.__init__(self)self.ui Ui_MainWindow()self.ui.setupUi(self)self.ui.pushButton.clicked.connect(self.btn_action)def btn_action(self):Ci_pai_name self.ui.textEdit_1.toPlainText()ret create_Songci(Ci_pai_name)self.ui.textEdit_2.setText() #写入空,清除作用self.ui.textEdit_2.setText(ret) #写入def create_Songci(Ci_pai_name):file1 open(rD:\a表格\课件\大三上\自然语言处理\实验\实验一\单字词.txt, r, encodingutf-8)file2 open(rD:\a表格\课件\大三上\自然语言处理\实验\实验一\双字词.txt, r, encodingutf-8)file1 file1.read().replace(\n,\t).split(\t) #[人, 13449, 风, 12875, 花, 11627, 一, 11502]file2 file2.read().replace(\n,\t).split(\t)# 返回的字符串 \t\n控制输出格式ret_str \t\t Ci_pai_name \n \n# 根据词牌名查找输出格式。file3 open(rD:\a表格\课件\大三上\自然语言处理\实验\Ci.txt, r, encodingutf-8)file3 file3.read().split(\n)file3 [x for x in file3 if x ! ]# print(file3) #[酒泉子, 长忆钱塘不是人寰是。]# 寻找词牌的位置try:id file3.index(Ci_pai_name)except:#沒找到return 词库未找到该词牌名# 词牌格式是id1的位置item file3[id1]count_tmp 0 #记录每个短句的个数Ci_form [] # 词的格式[4, , 7, 。, 7, 。, 5, 。, 7, 。, 7, 。, 7, 。, 5, 。]for i in range(len(item)):if item[i] in 。、( ):Ci_form.append(count_tmp)Ci_form.append(item[i])count_tmp 0else:count_tmp 1print(Ci_form,Ci_form)#[4, , 7, 。, 7, 。, 5, 。, 7, 。, 7, 。, 7, 。, 5, 。]# 按照格式随机选择生成词for item in Ci_form:print(item)if str(item) in 。、(){}:“” :ret_str item# 第一次写的废物代码n个if# else:# if item 2:# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 三个字# elif item 3:# tmp random.randint(0,2*len(file1))# ret_str file1[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 因为字典是#[人, 13449, 风, 12875, 花, 11627, 一, 11502]# # 保证是汉字而不是数字下面同理# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 四个字# elif item 4:# for i in range(2):# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 五个字# elif item 5:# for i in range(3):# if i1:# tmp random.randint(0,2*len(file1))# ret_str file1[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# else:# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 六个字# elif item 6:# for i in range(3):# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# # 七个字# elif item 7:# for i in range(4):# if i2:# tmp random.randint(0,2*len(file1))# ret_str file1[tmp//2 if (tmp//2)%20 else (tmp//2)-1]# else:# tmp random.randint(0,2*len(file2))# ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]else:while item 0:R_int random.randint(1,3)if item - R_int 0: #可以填词if R_int 1: #加一个词tmp random.randint(0,2*len(file1))ret_str file1[tmp//2 if (tmp//2)%20 else (tmp//2)-1]item - 1else:# 加两个词tmp random.randint(0,2*len(file2))ret_str file2[tmp//2 if (tmp//2)%20 else (tmp//2)-1]item - 2print(ret_str)print(ret_str)return ret_strdef main():create_Songci(酒泉子)if __name__ __main__:app QtWidgets.QApplication(sys.argv)mywindow Mywindow()mywindow.show()sys.exit(app.exec_())
main()实验三 Main.py Author: Martin
Date: 2022-10-17 21:18:40中文词频统计
语料库:1998-01-2003版-带音.txt
要求:输入txt文件,统计1元模型和2元模型,输出单词和词频文件,双词和词频文件。设计相应的接口,能够快速载入文件,并检索单词和双词。import re
import collectionsfile_path_in rD:\a表格\课件\大三上\自然语言处理\实验\199801.txt
file_path_out_1 rD:\a表格\课件\大三上\自然语言处理\实验\实验三\单词.txt
file_path_out_2 rD:\a表格\课件\大三上\自然语言处理\实验\实验三\双词.txttext []
oneWords []
twoWords []
one_counter_list []
two_counter_list []def get_one_and_two_word():读入文件写入文件global one_counter_listglobal two_counter_listglobal oneWordsglobal twoWords# 读文件with open(file_path_in,r,encodingutf-8) as fp:line fp.read().split(\n)# 去掉词性存入列表for one in line:fil re.compile((/[a-z]*\\s{0,}))one fil.split(one)one one[1:] #去掉 时间one one[1::2] #去掉 /mtest []test.append(b)# 去掉括号for i in range(len(one)):word one[i]fil re.compile(r\{.*?\}|\[.*?\]|\.*?\)word fil.sub(, word)word .join(word)if len(word) 1:continuetest.append(word)test.append(e)# 除了be还有字if len(test) 2:text.append(test)#print(text) #[[[b, 迈向, 充满, 希望, 的, 新, 世纪, ——, 一九九八年, # 新年, 讲话, , 附, 图片, , 张, , e], [b, 中共中央]# 把单词和双词存入列表for line in text:for i in range(len(line)):if not line[i] b and not line[i] e:oneWords.append(line[i])if i 1 len(line):twoWords.append(line[i] line[i1])global one_counter_listglobal two_counter_listone_counter_list collections.Counter(oneWords)two_counter_list collections.Counter(twoWords)one_counter_dict dict(one_counter_list)two_counter_dict dict(two_counter_list)# 对字典排序变成[(word,num),(word,num)]tmp_dict sorted(one_counter_dict.items(),keylambda x : x[1],reverseTrue)with open(file_path_out_1,w,encodingutf-8) as fp:for item in tmp_dict:fp.write(item[0])fp.write(\t)fp.write(str(item[1]))fp.write(\n)tmp_dict sorted(two_counter_dict.items(),keylambda x : x[1],reverseTrue)with open(file_path_out_2,w,encodingutf-8) as fp:for item in tmp_dict:# print(item)fp.write(item[0])fp.write(\t)fp.write(str(item[1]))fp.write(\n)
def main():get_one_and_two_word()while True:name input(请输入你要查找的词)if (one_counter_list[name] 0) and (two_counter_list[name] 0):print(未找到该词请重新输入)elif two_counter_list[name] ! 0:print(该单词是双词)print(该词数量为:, two_counter_list[name])elif one_counter_list[name] ! 0:print(该单词是单词)print(该词数量为:, one_counter_list[name])if __name__ __main__:main()实验四 main.py Author: Martin
Date: 2022-10-17 22:36:19
中文词法分析系统
语料库:1998-01-2003版-带音.txt
要求:根据构建的单词词典和双词词典,用n-gram模型,或者前向最长匹配,或者后向最长匹配等算法,
鼓励用更复杂一些的方法来进行,包括隐马尔科夫模型和条件随机场模型。
file_path_in rD:\a表格\课件\大三上\自然语言处理\实验\199801.txt
file_path_out_1 rD:\a表格\课件\大三上\自然语言处理\实验\实验三\单词.txt
file_path_out_2 rD:\a表格\课件\大三上\自然语言处理\实验\实验三\双词.txtfile1 open(file_path_out_1, r, encodingutf-8)
file2 open(file_path_out_2, r, encodingutf-8)
file1 file1.read().replace(\n,\t).split(\t) #[人, 13449, 风, 12875, 花, 11627, 一, 11502]
file2 file2.read().replace(\n,\t).split(\t)file1_dict dict(zip(file1[0::2],file1[1::2])) #{: 73350, 的: 53572}
file2_dict dict(zip(file2[0::2],file2[1::2]))
# 合并两个词典
mix_file1_and_file2_dict {**file1_dict,**file2_dict}
# print(mix_file1_and_file2_dict.keys())#实验四利用最大向前对句子进行切分
def Get_max_forword_split_sentence(texts):import re# 分句result_text []texts re.split((|。|| ||),texts)for text in texts:# 初始化索引text_begin 0 #句子的开始text_end len(text) #句子的结束while text_begin len(text):if text_begin text_end:# 如果存在最长的匹配if text[text_begin:text_end] in mix_file1_and_file2_dict.keys():#print(text[text_begin:text_end])tmp_string text[text_begin:text_end]result_text.append(tmp_string)text_begin len(tmp_string)text_end len(text)# 如果不存在else:text_end - 1# 匹配完成else:# 就剩一个字了语料库也没找到直接入#result_text.append(text[text_end])text_begin 1res for word in result_text:res word /return res
#实验四利用最大后向对句子进行切分
def Get_max_backword_split_sentence(texts):import re# 分句result_text []texts re.split((|。|| ||),texts)for text in texts:text_begin 0text_end len(text)while text_end 0:if text_begintext_end:# 如果存在最长的匹配if text[text_begin:text_end] in mix_file1_and_file2_dict.keys():# print(text[text_begin:text_end])tmp_string text[text_begin:text_end]result_text.append(tmp_string)text_end - len(tmp_string)text_begin 0# 如果不存在else:text_begin 1# 匹配完成else:# 就剩一个字了语料库也没找到直接入#result_text.append(text[text_begin])text_end - 1 res for word in result_text[::-1]:res word /return res
def main():textsssssssss [中国的合作交流不断扩大经济实力不断增强要坚强]textsssssssss [我是一名计算机专业的学生]textsssssssss [双向最大匹配法是将正向最大匹配法得到的分词结果和逆向最大匹配法得到的结果进行比较]for texts in textsssssssss:forword Get_max_forword_split_sentence(texts)backword Get_max_backword_split_sentence(texts)# backword w /ni/我·print(利用最大向前对句子进行切分: ,forword)print(利用最大后向对句子进行切分: ,backword)one_word_in_forword len([x for x in forword.split(/) if len(x)1])one_word_in_backword len([x for x in backword.split(/) if len(x)1])print(one_word_in_forword,one_word_in_backword)if one_word_in_forwordone_word_in_backword:print(系统认为最大后向匹配较好)return forwordprint(系统认为最大前向匹配较好)return backword#Max_forword_split_sentence
if __name__ __main__:main()