第一章数据库基础知识
本章以概念为主,主要是了解数据库的基本概念,数据库技术的发展,数据模型,重点是关系型数据。
第一节:信息,数据与数据处理
一、信息与数据:
1、信息:是现实世界事物的存在方式或运动状态的反映。或认为,信息是一种已经被加工为特定形式的数据。
信息的主要特征是:信息的传递需要物质载体,信息的获取和传递要消费能量;信息可以感知;信息可以存储、压缩、加工、传递、共享、扩散、再生和增值
2、数据:数据是信息的载体和具体表现形式,信息不随着数据形式的变化而变化。数据有文字、数字、图形、声音等表现形式。
3、数据与信息的关系:一般情况下将数据与信息作为一个概念而不加区分。
二、数据处理与数据管理技术:
1、数据处理:数据处理是对各种形式的数据进行收集、存储、加工和传输等活动的总称。
2、数据管理:数据收集、分类、组织、编码、存储、检索、传输和维护等环节是数据处理的基本 *** 作,称为数据管理。数据管理是数据处理的核心问题。
3、数据库技术所研究的问题不是如何科学的进行数据管理。
4、数据管理技术的三个阶段:人工管理,文件管理和数据库系统。
第二节:数据库技术的发展
一、数据库的发展:数据库的发展经历了三个阶段:
1、层次型和网状型:
代表产品是1969年IBM公司研制的层次模型数据库管理系统IMS。
2、关系型数据型库:
目前大部分数据库采用的是关系型数据库。1970年IBM公司的研究员E.F.Codd提出了关系模型。其代表产品为sysemR和Inges。
3、第三代数据库将为更加丰富的数据模型和更强大的数据管理功能为特征,以提供传统数据库系统难以支持的新应用。它必须支持面向对象,具有开放性,能够在多个平台上使用。
二、数据库技术的发展趋势:
1、面向对象的方法和技术对数据库发展的影响:
数据库研究人员借鉴和吸收了面向对旬的方法和技术,提出了面向对象数据模型。
2、数据库技术与多学科技术的有机组合:
3、面向专门应用领域的数据库技术
三、数据库系统的组成:
数据库系统(DBS)是一个采用数据库技术,具有管理数据库功能,由硬件、软件、数据库及各类人员组成的计算机系统。
1、数据库(DB):
数据库是以一定的组织方式存放于计算机外存储器中相互关联的数据集合,它是数据库系统的核心和管理对象,其数据是集成的、共享的以及冗余最小的。
2、数据库管理系统(DBMS):
数据库管理系统是维护和管理数据库的软件,是数据库与用户之间的界面。作为数据库的核心软件,提供建立、 *** 作、维护数据库的命令和方法。
3、应用程序:
对数据库中数据进行各种处理的程序,由用户编写。
4、计算机软件:
5、计算机硬件:
包括CPU、内存、磁盘等。要求有足够大的内存来存放 *** 作系统、数据库管理系统的核心模块以及数据库缓冲;足够大的磁盘能够直接存取和备份数据;比较主的通道能力;支持联网,实现数据共享。
6、各类人员。
四、数据库系统的特点:
1、数据共享:
2、面向全组织的数据结构化:
数据不再从属于一个特定应用,而是按照某种模型组织成为一个结构化的整。它描述数据要身的特性,也描述数据与数据之间的种种联系。
3、数据独立性:
4、可控数据冗余度:
5、统一数据控制功能:
数据安全性控制:指采取一定的安全保密措施确保数据库中的数据不被非法用户存取而造成数据的泄密和破坏;
数据完整性控制:是指数据的正确性、有效性与相容性。
并发控制:多个用户对数据进行存取时,采取必要的措施进行数据保护;
数据恢复:系统能进行应急处理,把数据恢复到正确状态。
第三节:数据模型
一、数据组织:
关系型数据库中的数据层次如下:
1、数据项(field):又称字段,用于描述实体的一个属性,是数据库的基本单位。一般用属性名作项名;
2、记录(Record):又称为结点,由若干个数据项组成,用于描述一个对象;
3、文件(File):由若干个记录组成;
4、数据库(DataBase):由逻辑相关的文件组成。
二、数据模型:
数据的组织形式称为数据模型,它决定数据(主要是结点)之间联系的表达方式。主要包括层次型、网状型、关系型和面向对象型四种。层次型和网状型是早期的数据模型,又称为格式化数据系统数模型。
以上四种模型决定了四种类型的数据库:层次数据库系统,网状数据库系统,关系型数据库系统以及面向对象数据库系统。
目前微机上使用的主要是关系型数据库。
1、层次型:是以记录为结点的有向树;图如教材P7图1--2
2、网状型:树的集合,它的表示能力以及精巧怀强于层次型,但独立性下降。
3、关系型:
在关系型中,数据被组织成若干张二维表,每张表称为一个关系。
一张表格中的一列称为一个“属性”,相当于记录中的一个数据项(或称为字段),属性的取值范围称为域。
表格中的一行称为一个“元组”,相当于记录值。
可用一个或若干个属性集合的值标识这些元组,称为“关键字”。
每一行对应的属性值叫做一个分量。
表格的框架相当于记录型,一个表格数据相当于一个同质文件。所有关系由关系的框架和若干元组构成,或者说关系是一张二维表。
关系型的特点:描述的一致性;可直接表示多对多关系;关系必须是规范化的;关系模型建立在数学概念基础上。
4、面向对象型:主要采用对象和灯的概念。
第四节:关系型数据库
一、关系型数据库的发展:
1、数据库产品种类繁多:像dBASE,FoxBASE,Clipper,Paradox,Acess等。
2、采用SQL语言:SQL(StructuredQueryLanguage)“结构化查询语言”,是通用的关系型数据库 *** 作语言,可以查询、定义、 *** 纵和控制数据库。它是一种非过程化语言。
3、支持面向对象的程序设计:
4、提供良好的图形界面和窗口;
5、支持开放的客户机/服务器和分布式处理;
6、提供新一代的数据库管理系统开发工具:支持GUI(图形界面)、ODBC(开放数据库连接)、OLE(对象的链接与嵌入)、DLL(动态链接)等。
二、关系型数据库管理系统(RDBMS)及其产品:
主要著名的关系型数据库产品有Oracle、Sybase、Informix、DB2、Inges、Paradox、Access、SQLServer等。数据库应用系统开发工具是PowerBuilder和Delphi。
如果查询缓存没有命中,那么SQL请求会进入分析器,分析器是用来分辨SQL语句的执行目的,其执行过程大致分为两步:
表1 语法分析关键字然后再通过语法规则解析,判断输入的SQL 语句是否满足MySQL语法,并且生成图5的语法树。由SQL语句生成的四个单词中,识别出两个关键字,分别是select 和from。根据MySQL的语法Select 和 from之间对应的是fields 字段,下面应该挂接username;在from后面跟随的是Tables字段,其下挂接的是userinfo。
优化器的作用是对SQL进行优化,生成最有的执行方案。如图6所示,前面提到的SQL解析器通过语法分析和语法规则生成了SQL语法树。这个语法树作为优化器的输入,而优化器(**的部分)包含了逻辑变换和代价优化两部分的内容。在优化完成以后会生成SQL执行计划作为整个优化过程的输出,交给执行器在存储引擎上执行。
所处的位置如上图所示,这节的重点在优化器中的逻辑变换和代价优化上。
逻辑变换也就是在关系代数基础上进行变换,其目的是为了化简,同时保证SQL变化前后的结果一致,也就是逻辑变化并不会带来结果集的变化。其主要包括以下几个方面:
这样讲概念或许有些抽象,通过图7 来看看逻辑变化如何在SQL中执行的吧。
如图7所示,从上往下共有4个步骤:
1 针对存在的SQL语句,首先通过“否定消除”,去掉条件判断中的“NOT”。语句由原来的“or”转换成“and”,并且大于小于符号进行变号。蓝色部分为修改前的SQL,红色是修改以后的SQL。2 等值传递,这一步很好理解分别降”t2a=9” 和”t2b=5”分别替换掉SQL中对应的值。3 接下来就是常量表达式计算,将“5+7”计算得到“12”。4 最后是常量表达式计算后的化简,将”9<=10”化简为”true”带入到最终的SQL表达式中完成优化。
代价优化是用来确定每个表,根据条件是否应用索引,应用哪个索引和确定多表连接的顺序等问题。为了完成代价优化,需要找到一个代价最小的方案。因此,优化器是通过基于代价的计算方法来决定如何执行查询的(Cost-based Optimization)。简化的过程如下:
这里将配置 *** 作的代价分为MySQL 服务层和MySQL 引擎层,MySQL 服务层主要是定义CPU的代价,而MySQL 引擎层主要定义IO代价。MySQL 57 引入了两个系统表mysqlserver_cost和mysqlengine_cost来分别配置这两个层的代价。如下:MySQL 服务层代价保存在表server_cost中,其具体内容如下:
由上可以看出创建临时表的代价是很高的,尤其是内部的myisam或innodb临时表。MySQL 引擎层代价保存在表engine_cost中,其具体内容如下:
目前io_block_read_cost和memory_block_read_cost默认值均为1,实际生产中建议酌情调大memory_block_read_cost,特别是对普通硬盘的场景。MySQL会根据SQL查询生成的查询计划中对应的 *** 作从上面两张代价表中查找对应的代价值,并且进行累加形成最终执行SQL计划的代价。再将多种可能的执行计划进行比较,选取最小代价的计划执行。
当分析器生成查询计划,并且经过优化器以后,就到了执行器。执行器会选择执行计划开始执行,但在执行之前会校验请求用户是否拥有查询的权限,如果没有权限,就会返回错误信息,否则将会去调用MySQL引擎层的接口,执行对应的SQL语句并且返回结果。例如SQL:“SELECT FROM userinfo WHERE username = 'Tom';“假设 “username“ 字段没有设置索引,就会调用存储引擎从第一条开始查,如果碰到了用户名字是” Tom“, 就将结果集返回,没有查找到就查看下一行,重复上一步的 *** 作,直到读完整个表或者找到对应的记录。需要注意SQL语句的执行顺序并不是按照书写顺序来的,顺序的定义会在分析器中做好,一般是按照如下顺序:
如果命中的记录比较多,应用会从MySql Server一批批获取数据
本文从MySQL中SQL语句的执行过程作为切入点,首先介绍了查询请求的执行流程,其中将MySQL的处理分为MySQL Server层和MySQL存储引擎层。通过介绍SQL语句的流转,引出了后面要介绍的5大组件,他们分别是:连接器、查询缓存、分析器、优化器、执行器。后面的内容中对每个组件进行了详细的介绍。连接器,负责身份认证和权限鉴别;查询缓存,将查询的结果集进行缓存,提高查询效率;分析器,对SQL语句执行语法分析和语法规则,生成语法树和执行计划;优化器,包括逻辑变换和代价优化;执行器,在检查用户权限以后对数据进行逐条查询,整个过程遵守SQL语句的执行顺序。
句法分析的基本任务是确定句子的 语法结构 或句子中 词汇之间的依存关系 。句法分析不是一个自然语言处理任务的最终目标,但它往往是实现最终目标的关键环节。
句法分析分为 句法结构分析 和 依存关系分析 两种。以获取整个句子的句法结构为目的的称为 完全句法分析 ,而以获得局部成分为目的的语法分析称为 局部分析 ,依存关系分析简称 依存分析 。
一般而言,句法分析的任务有三个:
判断输出的字符串是否属于某种语言
消除输入句子中词法和结构等方面的歧义
分析输入句子的内部结构,如成分构成、上下文关系等。
第二三个任务一般是句法分析的主要任务。
一般来说,构造一个句法分析器需要考虑两部分工作:一部分是语法的形式化表示和词条信息描述问题,形式化的语法规则构成了规则库,词条信息等由词典或同义词表等提供,规则库与词典或同义词表构成了句法分析的知识库;另一部分就是基于知识库的解析算法了。
语法形式化属于句法理论研究的范畴,目前在自然语言处理中广泛使用的是上下文无关文法(CFG)和基于约束的文法,后者又称合一文法。
简单的讲,句法结构分析方法可以分为基于规则的分析方法和基于统计的分析方法两大类。
基于规则的句法结构分析方法的基本思路是,由人工组织语法规则,建立语法知识库,通过条件约束和检查来实现句法结构歧义的消除。
根据句法分析树形成方向的区别,人们通常将这些方法划分为三种类型:自顶向下的分析方法,自底向上的分析方法和两者相结合的分析方法。自顶向下分析算法实现的是规则推导的过程,分析树从根结点开始不断生长,最后形成分析句子的叶结点。而自底向上分析算法的实现过程恰好想法,它是从句子符号串开始,执行不断规约的过程,最后形成根节点。
基于规则的语法结构分析可以利用手工编写的规则分析出输入句子所有可能的句法结构;对于特定领域和目的,利用有针对性的规则能够较好的处理句子中的部分歧义和一些超语法(extra-grammatical)现象。
但对于一个中等长度的输入句子来说,要利用大覆盖度的语法规则分析出所有可能的句子结构是非常困难的,而且就算分析出来了,也难以实现有效的消歧,并选择出最有可能的分析结果;手工编写的规则带有一定的主观性,还需要考虑到泛化,在面对复杂语境时正确率难以保证;手工编写规则本身就是一件大工作量的复杂劳动,而且编写的规则领域有密切的相关性,不利于句法分析系统向其他领域移植。
基于规则的句法分析算法能够成功的处理程序设计语言的编译,而对于自然语言的处理却始终难以摆脱困境,是因为程序设计语言中使用的知识严格限制的上下文无关文法的子类,但自然语言处理系统中所使用的形式化描述方法远远超过了上下文无关文法的表达能力;而且人们在使用程序设计语言的时候,一切表达方式都必须服从机器的要求,是一个人服从机器的过程,这个过程是从语言的无限集到有限集的映射过程,而在自然语言处理中则恰恰相反,自然语言处理实现的是机器追踪和服从人的语言,从语言的有限集到无限集推演的过程。
完全语法分析
基于PCFG的基本分析方法
基于概率上下文无关文法的短语结构分析方法,可以说是目前最成功的语法驱动的统计句法分析方法,可以认为是规则方法与统计方法的结合。
PCFG是CFG的扩展,举个例子:
PCFG
当然,同一个符号不同生成式的概率之和为1。NP是名词短语、VP是动词短语、PP是介词短语。
基于PCFG的句法分析模型,满足以下三个条件:
位置不变性:子树的概率不依赖于该子树所管辖的单词在句子中的位置
上下文无关性:子树的概率不依赖于子树控制范围以外的单词
祖先无关性:子树的概率不依赖于推导出子树的祖先节点
根据上述文法,『He met Jenny with flowers』有两种可能的语法结构:
而且我们可以通过将树中的所有概率相乘,得到两棵子树的整体概率,从中选择概率更大的子树作为最佳结构。
与HMM类似,PCFG也有三个基本问题:
给定一个句子W=w1w2…wn和文法G,如何快速计算概率P(W|G)
给定一个句子W=w1w2…wn和文法G,如何选择该句子的最佳结构?即选择句法结构树t使其具有最大概率
给定PCFG G和句子W=w1w2…wn,如何调节G的概率参数,使句子的概率最大
首先是第一个问题,HMM中我们用的是前向算法和后向算法来计算观察序列O概率,相似的,这里我们用的是内向算法和外向算法来计算P(W|G) 。
首先我们定义内向变量αij(A),与前向变量相似但又有不同,αij(A)即非终结符A推导出W中字串wiw(i+1)…wj的概率。那P(W|G)自然就等于α1n(S)了,S是起始符号,计算的就是由起始符号S推导出整个句子W=w1w2…wn的概率。
所以只要有αij(A)的递归公式就能计算出P(W|G),递归公式如下:
根据定义,αii(A)自然就等同于符号A输出wi的概率;而αij(A)的计算思路是,这个子串wiw(i+1)…wj可以被切成两部分处理,前一部分wiw(i+1)…wk由非终结符号B生成,后一部分wkw(k+1)…wj由非终结符号C生成,而BC由A生成。这样将概率依次相乘,即可将一个大问题划分为两个小问题处理,两个小问题又可以进一步划分直到不能划分为止,然后递归回来得到结果。
这里给一张内向变量计算方法示意图:
这个问题也可以用外向算法来解决。
首先定义外向变量,βij(A)是,初始符号S在推导出语句W=w1w2…wn的过程中,产生符号串w1w2…w(i-1)Aw(j+1)…wn的概率(隐含着A会生成wiw(i+1)…wj)。也就是说βij(A)是S推导出除了以A节点为根节点的子树以外的其他部分的概率。
《统计自然语言处理(第二版)》这本书里讲错了,这里我给出我自己的理解,书里给的算法步骤如下:
很明显的错误,初始化都把结果初始化了,那这个算法还算什么,直接等于1就完了呗。
这是作者对外向变量定义理解模糊的问题,上面给了外向变量的定义,里面有一句话『隐含着A会生成wiw(i+1)…wj』,那问题在于,A会生成wiw(i+1)…wj,这到底算是条件还是推论。
看这个算法的初始化的意思,说β1n(A),在A=S的时候,为1,不等于S为0,意思是什么?意思就是『隐含着A会生成wiw(i+1)…wj』这句话是条件,β1n(S)已经隐含了S生成W=w1w2…wn了,所谓的w1w2…w(i-1)Aw(j+1)…wn也就不存在了,只剩下一个S->S了,所以概率自然为1。
但是在第三步这个地方,作者理解成什么意思了呢?作者又把『隐含着A会生成wiw(i+1)…wj』这句话当成推论了,认为在β1n(S),里S会生成W=w1w2…wn是推论,那真是就正好了,要求的结果就是S生成W=w1w2…wn,这不就结束了吗,结果就导致了这个算法第一步初始化都把结果初始化了。
那我的理解是什么呢,通过这个公式计算出来的β1n(S),确实是正确的,意义实际上也是包含了『隐含着A会生成wiw(i+1)…wj』这句话是推论,但是右侧式子里由于不断递归而产生的β1n(S),是把『隐含着A会生成wiw(i+1)…wj』这句话当条件的,所以计算上没有问题。
我倾向于为第三步中的β1n(S)加一个星号,以表明意义的不同。
书中还给了个外向变量的计算方法示意图,我觉得也是莫名其妙:
他说βij(A)是这两种情况的概率和,这我们知道j比i大,那这图里这个k既比i小又比j大,这不是搞笑吗。只能说图上这俩C就不是一个C,k也不是一个k。
那我为什么会理解成一个呢,除了字母相同,他前面还这么讲『必定运用了形如B->AC或者B->CA的规则』、『运用B->AC或者B->CA两种规则的情况』,这明显就是给人以顺序交换的误解。
另外,还在内向变量的使用上前后不一,可以说这本书里对外向算法的讲解是非常失败的。而且对外向算法的计算仍然需要用到内向算法的递归,那真的直接用内向算法就好了,外向算法还要多定义变量。
然后是第二个问题,选择句子的最佳结构,也即给定一个句子W=w1w2…wn和文法G,
选定拥有最大概率的语法结构树。这一问题与HMM中类似,仍然采用动态规划的思想去解决。最后利用CYK算法去生成拥有最大概率的语法结构树。
第三个问题是给定PCFG G和句子W=w1w2…wn,如何调节G的概率参数,使句子的概率最大,与HMM相对的,PCFG这里采用的算法名叫内外向算法。与前后向算法相同,也属于一种EM算法,其基本思想是,首先给G的产生式随机地赋予一个概率值(满足归一化条件),得到文法G0,然后根据G0和训练数据,可以计算出每条规则使用次数的期望值,用期望值进行最大似然估计,得到语法G的新参数值,新的语法记作G1,然后循环执行该过程,G的参数概率将收敛于最大似然估计值。
PCFG只是一种特殊的上下文无关文法模型,根据PCFG的模型和句子,具体去对句子做语法分析,生成语法结构树,靠的是还是CYK算法。CYK算法是一个用来判定任意给定的字符串W是否属于一个上下文无关文法的算法。
基于PCFG的句法分析模型存在有许多问题,比如因为PCFG没有对词汇进行建模,所以存在对词汇信息不敏感的问题。因此人们提出了词汇化的短语结构分析器,有效的提升了基于PCFG的句法分析器的能力。
而且,我们上面也提到了PCFG的三个独立性假设,这也导致了规则之间缺乏结构依赖关系(就像HMM的三个假设也不完全合理一样),而在自然语言中,生成每个非终结符的概率往往是与其上下文结构有关系的,所以有人提出了一种细化非终结符的方法,为每个非终结符标注上其父节点的句法标记信息。
D Klein提出了带有隐含标记的上下文无关文法(PCFG with latent annotations,PCFG-LA),使得非终结符的细化过程可以自动进行,并且在使用EM算法优化时,为避免到达局部最优,对其进行了改进,提出了一种层次化的『分裂-合并』策略,以期获取一个准确并且紧凑的PCFG-LA模型。基于PCFG-LA的Berkeley Parser作为非词汇化句法分析器的代表,无论是性能表现还是运行速度,都是目前开源的短语结构分析器中最好的。其语法树如下图:
普通句法树与PCFG-LA句法树对照实例
这个x就是隐含标记,xi的取值范围一般是人为设定的,一般取1~16之间的整数。而且PCFG-LA也类似于HMM模型,原始非终结符对应HMM模型中的观察输出,而隐含标记对应HMM模型中的隐含状态。
浅层语法分析(局部语法分析)
由于完全语法分析要确定句子所包含的全部句法信息,并确定句子中各成分之间的关系,这是一项十分苦难的任务。到目前为止,句法分析器的各方面都难以达到令人满意的程度,为了降低问题的复杂度,同时获得一定的句法结构信息,浅层句法分析应运而生。
浅层语法分析只要求识别句子中的某些结构相对简单的独立成为,例如非递归的名词短语、动词短语等,这些被识别出来的结构通常称为语块(chunk)。
浅层句法分析将句法分析分解为两个主要子任务,一个是语块的识别和分析,另一个是语块之间的依附关系分析。其中,语块的识别和分析是主要任务。在某种程度上说,浅层句法分析使句法分析的任务得到了简化,同时也有利于句法分析系统在大规模真实文本处理系统中迅速得到应用。
基本名词短语(base NP)是语块中的一个重要类别,它指的是简单的、非嵌套的名词短语,不含有其他子项短语,并且base NP之间结构上是独立的。示例如下:
base NP识别就是从句子中识别出所有的base NP,根据这种理解,一个句子中的成分和简单的分为baseNP和非base NP两类,那么base NP识别就成了一个分类问题。
base NP的表示方法有两种,一种是括号分隔法,一种是IOB标注法。括号分隔法就是将base NP用方括号界定边界,内部的是base NP,外部的不属于base NP。IOB标注法中,字母B表示base NP的开端,I表示当前词语在base NP内,O表示词语位于base NP之外。
基于SVM的base NP识别方法
由于base NP识别是多值分类问题,而基础SVM算法解决的是二值分类问题,所以一般可以采用配对策略(pairwise method)和一比其余策略(one vs other method)。
SVM一般要从上下文的词、词性、base NP标志中提取特征来完成判断。一般使用的词语窗口的长度为5(当前词及其前后各两个词)时识别的效果最好。
基于WINNOW的base NP识别方法
WINNOW是解决二分问题的错误驱动的机器学习方法,该方法能从大量不相关的特征中快速学习。
WINNOW的稀疏网络(SNoW)学习结构是一种多类分类器,专门用于处理特征识别领域的大规模学习任务。WINNOW算法具有处理高维度独立特征空间的能力,而在自然语言处理中的特征向量恰好具有这种特点,因此WINNOW算法也常用于词性标注、拼写错误检查和文本分类等等。
简单WINNOW的基本思想是,已知特征向量和参数向量和实数阈值θ,先将参数向量均初始化为1,将训练样本代入,求特征向量和参数向量的内积,将其与θ比较,如果大于θ,则判定为正例,小于θ则判定为反例,将结果与正确答案作比较,依据结果来改变权值。
如果将正例估计成了反例,那么对于原来值为1的x,把它的权值扩大。如果将反例估计成了正例,那么对于原来值为1的x,把它的权值缩小。然后重新估计重新更改权重,直到训练完成。
这其实让我想到了LR算法,因为LR算法也是特征向量与参数向量的内积,最后将其送到Sigmoid函数中去拿到判定结果,然后大于05的为正例,小于05的为反例,实际上只要反过来,Sigmod函数输出05时候的输入就是WINNOW算法里的那个实数阈值θ。但是区别在于WINNOW算法只判定大小,不判定概率,而LR利用Sigmoid函数给出了概率。LR利用这给出的概率,通过使训练集的生成概率最大化来调整参数,而WINNOW则是直接朴素的错误情况来增大或缩小相关参数。目测LR因为使用了梯度下降,它的收敛速度要快于WINNOW,而WINNOW的优势则在于可以处理大量特征。
基于CRF的base NP识别方法
基于CRF的base NP识别方法拥有与SVM方法几乎一样的效果,优于基于WINNOW的识别方法、基于MEMM的识别方法和感知机方法,而且基于CRF的base NP识别方法在运行速度上较其他方法具有明显优势。
依存语法理论
在自然语言处理中,我们有时不需要或者不仅仅需要整个句子的短语结构树,而且要知道句子中 词与词之间的依存关系 。用词与词之间的依存关系来描述语言结构的框架成为依存语法,又称从属关系语法。利用依存语法进行句法分析也是自然语言理解的重要手段之一。
有人认为,一切结构语法现象可以概括为关联、组合和转位这三大核心。句法关联建立起词与词之间的从属关系,这种从属关系由 支配词 和 从属词 联结而成, 谓语中的动词是句子的中心并支配别的成分,它本身不受其他任何成分支配 。
依存语法的本质是一种结构语法,它主要研究以谓词为中心而构句时由深层语义结构映现为表层语法结构的状况及条件,谓词与体词之间的同现关系,并据此划分谓词的词类。
常用的依存于法结构图示有三种:
计算机语言学家J Robinson提出了依存语法的四条公理:
一个句子只有一个独立的成分
句子的其他成分都从属于某一成分
任何一个成分都不能依存于两个或两个以上的成分
如果成分A直接从属于成分B,而成分C在句子中位于A和B之间,那么,成分C或者属于成分A,或者从属于B,或者从属于A和B之间的某一成分。
这四条公理相当于对依存图和依存树的形式约束:单一父节点、连通、无环和可投射,由此来保证句子的依存分析结果是一棵有根的树结构。
这里提一下可投射,如果单词之间的依存弧画出来没有任何的交叉,就是可投射的(参考上面的两个有向图)。
为了便于理解,我国学者提出了依存结构树应满足的5个条件:
单纯结点条件:只有终结点,没有非终结点
单一父结点条件:除根节点没有父结点外,所有的结点都只有一个父结点
独根结点条件:一个依存树只能有一个根结点,它支配其他结点
非交条件:依存树的树枝不能彼此相交
互斥条件:从上到下的支配关系和从左到右的前于关系之间是相互排斥的,如果两个结点之间存在着支配关系,它们就不能存在于前于关系
这五个条件是有交集的,但它们完全从依存表达的空间结构出发,比四条公理更直观更实用。
Gaifman 1965年给出了依存语法的形式化表示,证明了依存语法与上下文无关文法没有什么不同
类似于上下文无关文法的语言形式对被分析的语言的投射性进行了限制,很难直接处理包含非投射现象的自由语序的语言。20世纪90年代发展起来了约束语法和相应的基于约束满足的依存分析方法,可以处理此类非投射性语言问题。
基于约束满足的分析方法建立在约束依存语法之上,将依存句法分析看做可以用约束满足问题来描述的有限构造问题。
约束依存语法用一系列形式化、描述性的约束将不符合约束的依存分析去掉,直到留下一棵合法的依存树。
生成式依存分析方法、判别式依存分析方法和确定性依存分析方法是数据驱动的统计依存分析中具有代表性的三种方法。
生成性依存分析方法
生成式依存分析方法采用联合概率模型生成一系列依存语法树并赋予其概率分值,然后采用相关算法找到概率打分最高的分析结果作为最后输出。
生成式依存分析模型使用起来比较方便,它的参数训练时只在训练集中寻找相关成分的计数,计算出先验概率。但是,生成式方法采用联合概率模型,再进行概率乘积分解时做了近似性假设和估计,而且,由于采用全局搜索,算法的复杂度较高,因此效率较低,但此类算法在准确率上有一定优势。但是类似于CYK算法的推理方法使得此类模型不易处理非投射性问题。
判别式依存分析方法
判别式依存分析方法采用条件概率模型,避开了联合概率模型所要求的独立性假设(考虑判别模型CRF舍弃了生成模型HMM的独立性假设),训练过程即寻找使目标函数(训练样本生成概率)最大的参数θ(类似Logistic回归和CRF)。
判别式方法不仅在推理时进行穷尽搜索,而且在训练算法上也具有全局最优性,需要在训练实例上重复句法分析过程来迭代参数,训练过程也是推理过程,训练和分析的时间复杂度一致。
确定性依存方法
确定性依存分析方法以特定的方向逐次取一个待分析的词,为每次输入的词产生一个单一的分析结果,直至序列的最后一个词。
这类算法在每一步的分析中都要根据当前分析状态做出决策(如判断其是否与前一个词发生依存关系),因此,这种方法又称决策式分析方法。
通过一个确定的分析动作序列来得到一个唯一的句法表达,即依存图(有时可能会有回溯和修补),这是确定性句法分析方法的基本思想。
短语结构与依存结构之间的关系
短语结构树可以被一一对应地转换成依存关系树,反之则不然。因为一棵依存关系树可能会对应多棵短语结构树。
近几年来 在TIOBE公司每个月发布的编程语言排行榜[ ]中 总是能挤进前 名 而在近 年的编程语言排行榜中 C#总体上呈现上升的趋势 C#能取得这样的成绩 有很多因素在起作用 其中 它在语言特性上的锐意进取让人印象深刻(图 )
图 C#各版本的创新点
年发布的C# 最大的创新点是拥有了动态编程语言的特性
动态编程语言的中兴
动态编程语言并非什么新鲜事物 早在面向对象编程语言成为主流之前 人们就已经使用动态编程语言来开发了 即使在 C# 等面向对象编程语言繁荣兴旺 大行于世的年代 动态编程语言也在 悄悄 地攻城掠地 占据了相当的开发领域 比如 业已成为客户端事实上的主流语言
最近这几年 动态编程语言变得日益流行 比如Python Ruby都非常活跃 使用者众多
这里有一个问题 为什么我们需要在开发中应用动态编程语言?与C#和Java这类已经非常成熟且功能强大的静态类型编程语言相比 动态编程语言有何优势?
简单地说 使用动态编程语言开发拥有以下的特性
( )支持REPL(Read evaluate print Loop 读入à执行à输出 循环迭代)的开发模式 整个过程简洁明了 直指问题的核心
举个简单的例子 图 所示为使用IronPython[ ]编程计算 + +……+ 的屏幕截图 我们可以快速地输入一段完成累加求和的代码 然后马上就可以看到结果
图 使用IronPython编程
如果使用开发就麻烦多了 您得先用Visual Studio创建一个项目 然后向其中添加一个类 在类中写一个方法完成求和的功能 再编写调用这一方法的代码 编译 排错 最后才能得到所需的结果……
很明显 对于那些短小的工作任务而言 动态编程语言所具备的这种REPL开发模式具有很大的吸引力
( )扩展方便 用户可以随时对代码进行调整 需要什么功能直接往动态对象上 加 就是了 不要时又可以移除它们 而且这种修改可以马上生效 并不需要像C#那样必须先修改类型的定义和声明 编译之后新方法才可用
换句话说 使用动态语言编程 不需要 重量级 的OOAD 整个开发过程迭代迅速而从不拖泥带水
( )动态编程语言的类型解析是在运行时完成的 可以省去许多不必要的类型转换代码 因此 与静态编程语相比 动态编程语言写的代码往往更紧凑 量更少
动态编程语言主要的弱点有两个
( )代码中的许多错误要等到运行时才能发现 而且需要特定的运行环境支持 对其进行测试不太方便 也不支持许多用于提升代码质量的各种工具 因此不太适合于开发规模较大的 包容复杂处理逻辑的应用系统
( )与静态编程语言相比 动态编程语言编写的程序性能较低 不过随着计算机软技术的不断进步 比如多核的广泛应用 动态编程语言引擎和运行环境不断地优化 动态编程语言编写的程序性能在不断地提升 在特定的应用场景下 甚至可以逼近静态语言编写的程序
拥抱 动态编程 特性的
为了让C# Visual Basic等编程语言能具备动态编程语言的特性 NET 引入了一个 DLR(Dynamic Language Runtime 动态语言运行时) (图 )
图 DLR 动态语言运行时
DLR运行于CLR之上 提供了一个动态语言的运行环境 从而允许Python Ruby等动态语言编写的程序在 NET平台上运行 同时 现有的 NET静态类型编程语言 比如C#和Visual Basic 也可以利用DLR而拥有一些动态编程语言的特性
( )使用C# 编写动态的代码
C# 新增了一个dynamic关键字 可以用它来编写 动态 的代码
例如 以下代码创建了一个ExpandoObject对象(注意必须定义为dynamic)
dynamic dynamicObj = new ExpandoObject();
这一对象的奇特之处在于 我们可以随时给它增加新成员
dynamicObj Value = ; //添加字段dynamicObj Increment = new Action(() => dynamicObj Value++); //添加方法
这些动态添加的成员与普通的类成员用法一样
for (int i = ; i < ; i++)dynamicObj Increment();//调用方法Console WriteLine( dynamicObj Value={ } dynamicObj Value);//访问字段
ExpandoObject对象实现了IDictionary<string object>接口 可看成是一个字典对象 所有动态添加的成员都是这个字典对象中的元素 这意味我们不仅可以添加新成员 还可以随时移除不再需要的成员
//移除Increment方法(dynamicObj as IDictionary<stringobject>) Remove( Increment );
方法移除之后 再尝试访问此方法将引发RuntimeBinderException异常
( )使用dynamic关键字简化与组件交互的代码
要在这个 托管世界 里调用 非托管世界 中的组件 我们必须通过 互 *** 作程序集(Interop Assembly) 作为桥梁 互 *** 作程序集 定义了CLR类型与类型之间的对应关系
只要给 NET项目添加对 互 *** 作程序集 的引用 就可以在 NET应用程序中创建这一程序集所包容的各种类型的实例(即包装器对象) 对这些对象的方法调用(或对其属性的存取)将会被转发给组件
以调用Word为例 在 之前您可能经常需要编写这样的代码
Object wordapp = new Word Application(); //创建Word对象Object fileName = MyDoc docx;//指定Word文档Object argu = System Reflection Missing Value;Word Document doc = wordapp Documents Open(ref fileNameref arguref arguref arguref arguref arguref arguref argu ref arguref arguref arguref arguref arguref arguref arguref argu);
上述对Open()方法的调用语句只能用 恐怖 一词来形容 其原因是Word组件中的Open()方法定义了太多的参数
使用dynamic关键字 配合从Visual Basic中学来的 命名参数与可选参数 这两个新语法特性 可以写出更简洁的代码
dynamic wordapp = new Word Application();dynamic doc = wordapp Documents Open(FileName: MyDoc docx );
上述代码中省去了用不着的参数 并且可以去掉参数前的ref关键字
当上述代码运行时 DLR会使用反射技术将dynamic表达式 绑定(bind) 到互 *** 作程序集中所包容的Word Application代理对象
( )C# 动态编程技术内幕
C# 中所定义的dynamic变量可以引用以下类型的对象
l 传统的 静态 的CLR对象
l 包装器对象 前面已经介绍了这方面的内容
l 实现了IDynamicMetaObjectProvider接口的 动态对象 ExpandoObject就是这种类型对象的实例
l 基于DLR实现的动态语言(比如IronRuby和IronPython)所创建的对象
从程序员角度来看 所有这四种对象都是一样的 都可用一个dynamic变量引用之 而DLR在程序运行时动态地将方法调用和字段存取请求 绑定 到真正的对象上
dynamic的功能是由DLR所支撑的 是C#编译器与DLR分工合作的成果
请看以下示例代码
dynamic d = ;d++;
C#编译器在处理上述代码时 它并不去检查变量d是否可以支持自增 *** 作 而是为其创建了一个CallSite<T>对象(<>p__Site )
private static class <Main>o__SiteContainer{public static CallSite<Func<CallSiteobjectobject>> <>p__Site ;}
中文MSDN将CallSite<T>译为 动态(调用)站点 它是DLR中的核心组件之一
动态站点对象通过CallSite<T> Create()方法创建 C#编译器会为其指定一个派生自CallSiteBinder的对象(称为 动态站点绑定对象 )作为其参数
动态站点绑定对象是与具体语言相关的 比如IronPython和C#都有各自的动态站点绑定对象
动态站点绑定对象的主要工作是将代码中的动态表达式(本例中为d++)转换为一棵 抽象语法树(AST Abstract Syntax Tree) 这棵语法树被称为 DLR Tree 是在 所引入的LINQ表达式树的基础上扩充而来的 因此 有时又称其为 表达式树(Expression Tree)
DLR在内部调用此表达式树的Compile()方法生成IL指令 得到一个可以被CLR所执行的委托(在本例中其类型就是Func<CallSite object object>)
动态调用站点对象(本例中为<>p__Site )有一个Target属性 它负责引用这一生成好的委托
委托生成之后 动态表达式的执行就体现为委托的执行 其实参由编译器直接 写死 在IL代码中
简化的代码示意如下(通过Reflector得到 为便于阅读 修改了变量名)
object d = ;object CS$ $= d;if (<>p__Site== null)<>p__Site= CallSite<Func<CallSiteobjectobject>> Create(……);d = <>p__Site Target(<>p__SiteCS$ $ );
上述类型推断 方法绑定及IL代码生成的工作都是在程序运行时完成的
( )动态代码很慢吗?
动态编程语言易学易用 代码紧凑 开发灵活 但性能则一直是它的 软肋 为了提升性能 DLR设计了一个三级缓存策略
动态站点绑定对象会为动态调用表达式转换而成的语法树加上相应的测试条件(称为 test ) 构成一个 规则(Rule) 这个规则可以用于判断某个语法树是否可用于特定的动态调用表达式
举个例子 请看以下这个动态表达式
d + d
如果在程序运行时d 和d 都是int类型的整数 则DLR生成的规则为
if( dis int && dis int) //测试条件return (int)d +(int)d ; //语法树
DLR通过检查规则中的 测试条件 就可以知道某个动态表达式是否可以使用此规则所包容的语法树
规则 是DLR缓存的主要对象
前面介绍过的动态站点对象Target属性所引用的委托是第一级缓存 它实现的处理逻辑是这样的
//当前处理规则 属于第 级缓存if( dis int && dis int) //测试条件return (int)d +(int)d ; //满足测试条件 直接返回一个表达式树//未命中 则在第 级 第 级缓存中查找 如果找到了 用找到的结果更新第 级缓存return site Update(site d d );
如果 级缓存中都没有命中的规则 则此动态站点所关联的调用站点绑定对象会尝试创建一个新的规则 如果创建新规则失败 则由当前编程语言(比如)所提供的默认调用站点绑定对象决定如何处理 通常的作法是抛出一个异常
当前版本的DLR第 级缓存了 条规则 第 级则缓存了 条规则
由于DLR自身设计了一个 规则 缓存系统 又充分利用了CLR所提供的JIT缓存(因为所有动态调用代码最终都会转换为CLR可以执行的IL指令 而CLR可以缓存这些代码) 使得动态代码仅仅在第一次执行时性能较差 后续的连续调用其性能可以逼近静态代码
C# 与动态语言的集成
由于几乎所有的编程语言都可以使用抽象语法树来表达 因此 在理论上DLR支持无限多种编程语言间的互 *** 作 在当前版本中 可以实现C#/Visual Basic与IronPython和IronRuby的互 *** 作 相信很快会出现其他动态编程语言的DLR实现
一个有趣的地方是当前基于DLR实现的动态编程语言都以 Iron 开头 比如IronRuby和IronPython IronPython的设计者 DLR的架构设计师Jim Hugunin曾经在微软PDC 大会上解释说主要是为了避免起一个 Python 或 Python for NET 之类 微软味十足 的名字 才有了 IronPython 他强调 Iron 系列动态语言将严格遵循动态语言自身的标准和规范 尊重这些动态语言已有的历史和积累 不会引入一些仅限于 NET平台的新语言特性 并且这些语言的 NET实现保持开源 与此同时 Jim Hugunin指出 Iron 系列语言能很好地与 NET现有类库 编程语言和工具集成 并且能 嵌入 到 NET宿主程序中
( )动态对象通讯协议
由于各种动态编程语言之间的特性相差极大 实现各语言间的互 *** 作是个难题 为此DLR采取了一个聪明的策略 它不去尝试设计一个 通用的类型系统 (CLR就是这么干的) 而是设计了一个 通用的对象通讯协议 规定所有需要互 *** 作的动态对象必须实现IDynamicMetaObjectProvider接口 此接口定义了一个GetMetaObject()方法 接收一个语法树对象作为参数 向外界返回一个 动态元数据(DynamicMetaObject) 对象
DynamicMetaObject GetMetaObject(Expression parameter);
DynamicMetaObject对象向外界提供了两个重要属性 Restrictions引用一组测试条件 Expression属性则引用一个语法树 这两个属性组合起来就是可供动态站点对象缓存的 规则(Rule)
DLR中的 动态站点绑定对象(CallSiteBinder) 获取了DynamicMetaObject对象之后 它调用此对象所提供的各个方法创建 规则 让 动态站点对象(CallSite<T>) 的Target属性引用它 完成动态绑定的工作
( )动态语言集成环境
为了方便地实现静态编程语言与各种动态编程语言间的相互集成 DLR提供了一整套称为 通用寄宿(Common Hosting) 的组件 其中包容ScriptRuntime ScriptScope等类型
下面我们以IronPython为例 介绍如何在 开发的程序中集成动态编程语言代码
首先需要创建一个ScriptRuntime对象 它是一个最顶层的对象 用于在一个应用程序域中 嵌入 一个特定动态语言的运行环境
ScriptRuntime pythonRuntime = Python CreateRuntime();
接着需要创建一个ScriptEngine对象 它是动态语言代码的执行引擎
ScriptEngine engine = pythonRuntime GetEngine( py );
ScriptScope对象类似于中的命名空间 其中可以通过定义一些变量向动态代码传入数据 比如下述代码将一个C# 创建的ExpandoObject对象传给Python代码
ScriptScope scope = pythonRuntime CreateScope();//C#创建动态对象 dynamic expando = new ExpandoObject();expando Name = JinXuLiang ; //动态添加一个字段 //让IronPython接收C#创建的Expando对象scope SetVariable( ExpandoObjectexpando);string pythonCode = print ExpandoObject Name ; //IronPython引擎执行Python语句engine CreateScriptSourceFromString(pythonCode) Execute(scope);
上述示例代码是直接执行Python代码 在实际开发中 更常见的是直接执行Python文件中的代码 假设有一个Calculator py文件 其中定义了一个Add函数
def Add(a b):return a+b
则以下C#代码可以直接执行之
ScriptRuntime pythonRuntime = Python CreateRuntime();dynamic pythonFile = pythonRuntime UseFile( Calculator py );Console WriteLine(pythonFile Add( ));
上述示例说明在DLR的支持之下 可以让静态编程语言使用动态语言所开发的库 反过来 基于DLR实现的动态编程语言也能使用为静态语言所设计的库 比如标准的基类库
这意味着两点
( )我们现在可以将 静态 和 动态 编程语言组合起来 开发出一些具有高度交互性的应用程序 使用静态编程语言搭建系统框架 使用动态编程语言实现交互性 这是一个很值得注意的应用领域
( )将来会出现一些 静态 动态 编程语言同时适用的库 向实现 无所不在的复用 目标又前进了一步
Visual Studio 为新的 NET编程语言F#提供了专门的项目模板 但没有为IronPython和IronRuby之类动态语言的开发提供支持 相信随着动态语言在 NET平台之上的应用日趋广泛 后继版本的Visual Studio会直接支持动态语言的开发
从C# ~ 所走过的路 可以很清晰地看到它的发展轨迹 得到这样的一个结论
未来的编程语言应该是多范式的 具有高度的可组合性 在一个项目或产品中组合多个编程语言 使用多种编程范式会变得越来越普遍
lishixinzhi/Article/program/ASP/201311/21813
以上就是关于数据库基础知识全部的内容,包括:数据库基础知识、MySql中Sql的执行过程、NLP第九篇-句法分析等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)