NLP从零开始------6基础文本处理之命名实体识别

1.命名实体识别介绍

        命名实体识别(Named Entity Recognition,NER)中的“命名实体”一般是指文本中具有特别意义或指代性非常强的实体(比如:人名,地名,时间或者机构组织等)。

         命名实体可分为实体类、时间类和数字类3大类,以及人名、机构名、地名、时间、日期、货币和百分比7小类。 命名实体识别在NLP中占有重要地位,它是信息提取、机器翻译和问答系统等应用领域里的基础工具。

         命名实体识别的任务就是识别出文本中的命名实体,通常分为实体边界识别和实体类别识别两个过程。 中文文本中没有类似英文文本中空格之类的显式标示词的边界标示符,也没有英文中较为明显的首字母大写标志的词,这使得中文的实体的边界识别变得更加有挑战性。

1.1命名实体识别困难

        中文实体识别的挑战性主要表现在以下3个方面。 中文词灵活多变。

        有些词语在不同语境下可能是不同的实体类型,如中国辽宁有个省市叫“沈阳”,中国也有一些人名叫“沈阳”,同一个词“沈阳”在不同语境下可以是地名或人名。有些词语在脱离上下文语境的情况下无法判断是否为命名实体,特别是一些带有特殊意义的人名如有人取名叫“白富美”,但“白富美”在脱离文本的情况下会认为是一个现代流行的形容词。

         中文词的嵌套情况复杂。一些中文的命名实体中常常嵌套另外一个命名实体。如“北京大学附属中学”这一组织机构名中还嵌套着同样可以作为组织机构名的“北京大学”、地名“北京”。命名实体的互相嵌套情况,对命名实体识别造成一定的困难。

         中文词存在简化表达现象。通常对一些较长的命名实体词进行简化表达,如“北京大学”通常简化为“北大”,“北京大学附属中学”通常简化为“北大附中”,无疑对命名实体的识别造成一定负担。

1.2命名实体识别本质

        命名实体识别实际上是序列标注问题。 命名实体识别领域常用的3种标注符号B、I、O分别代表实体开始、实体中间、其他。 在字一级的识别任务中,对于人名、地名、机构名的3种命名实体PER、LOC、ORG,定义7种标注的集合L={B-PER,I-PER,B-LOC,I-LOC,B-ORG,I-ORG,O},分别代表的是人名、地名、机构名的首部、内部和其他。 如“尼克松是出身于加利福尼亚的政治家”,标注序列为{ B-PER, I-PER, I-PER, O, O,O, O, B-LOC, I-LOC, I-LOC I-LOC, I-LOC, O, O, O, O }。

        假设x=x_1,x_2,⋯,x_n为待标注的字观测序列,\displaystyle s=\left \{ s1,s2,s3,... ,sn\right \} 为待标注的状态集合。命名实体识别问题可描述为求概率p(y|x)最大的状态序列 y=y_1,y_2,...,y_n,其中 y_i \in S,如下式子所示。

                                                 

         早期的命名实体识别主要是基于规则的方法,后来基于大规模语料库的统计方法逐渐成为主流。HMM、最大熵马尔可夫模型(Maximum Entropy Markov Model,MEMM)以及条件随机场(Conditional Random Field,CRF)是命名实体识别中最常用也是最基本的3个统计模型。 首先出现的是HMM,其次是MEMM,最后是CRF。

2.CRE模型

        CRF模型最早由Lafferty等人于2001年提出,其模型思想主要来源于最大熵模型。 CRF模型是一种基于统计方法的模型,可以被认为是一个无向图模型或一个马尔可夫随机场,它是一种用于   标记和切分序列化数据的统计框架模型。相对于HMM和MEMM,CRF模型没有HMM那样严格的独立性假设,同时克服了MEMM标记偏置的缺点。

        CRF理论在命名实体词识别、语句分词、词性标注等语言处理领域有着十分广泛深入的应用。 CRF与HMM不同,CRF中当前的状态不是只由这一时刻观测条件给出,而是与整个序列的整体状态相关,即CRF依赖于自己观测条件下的所有观测数值。 CRF在解决英语浅层分析、英文命名实体识别等任务时,取得了良好的效果。CRF的特性以及研究成果表明,它也能够适用于中文命名实体识别的研究任务。

2.1 线性链条件随机场

        假如一个随机变量序列 X=X1,X2,X3,...,Xn中各个节点之间的关系是呈线性的,则称序列X 是一个线性链。

        设  X=X1,X2,X3,...,XnY=Y1,Y2,Y3,...,Yn,均为线性链表示的随机变量序列。若在给定的观测序列X的条件下,随机变量序列Y的条件概率分布 P(Y|X) 满足马尔可夫性,如下式子所示。则称为P(Y|X)线性链条件随机场(linear-CRF)。

                                

        linear-CRF的结构如下图所示。

                         

2. 2linear-CRF参数化形式

        linear-CRF可以用于文本标注问题。条件概率p(Y│X)中, X表示输入观测序列,Y 表示对应的输出标记序列或状态序列。 模型在学习时,利用训练数据通过极大似然估计或正则化的极大似然估计得到条件概率模型p ̂ (Y│X)预测时,对于给定的输入序列 X,求出条件概率 p ̂ (Y│X)最大的输出序列。 如果将Y的每一个标注序列当作一个类别,那么可以将序列标注问题看做是多分类问题,即输入观测序列X ,求出条件概率p(Y│X)最大的类别。 多分类问题中,多项逻辑斯谛回归是最经典的一类模型,式子如下所示。

                                

        在上述式子中, x是特征向量,w为特征向量的权重。

         因为输入序列X一般是一段文本序列,所以机器学习算法是不能直接使用的,需要将它们转化成机器学习算法可以识别的数值特征,然后再交给机器学习的算法进行操作。对于序列标注问题,需要先对输入序列X进行特征提取。 上文式子可知,p(Y|X)条件概率分布与节点X, Y_{i-1}, Y_i, Y_{i+1}.有关,因此,构建的特征函数应该将这些节点信息特征提取出来。选取适当的特征是CRF一项重要任务,特征的选择可直接影响最终标注的质量。

         设随机变量X取值记为x ,Y取值记为y 。序列X的特征提取是通过构建特征函数完成的。特征函数包含四个参数,分别为文本x 、参数 i(表示文本x 中第 i个词)、y_{i}(第i个词的标注值)和y_{i+1}(第i+1 个词的标注值)。 因为linear-CRF满足马尔科夫性,所以只有上下文相关的局部特征函数,没有不相邻节点之间的特征函数

        特征函数分为两类,第一类是定义在Y上的转移特征函数t,这类特征函数只和当前节点yi和上一个节点yi-1有关,特征函数如下图所示。

                      

        第一类特征函数式子如下所示。其中,i表示当前节点在序列的位置, yi表示序列x 第 i个字的标注, K1 是定义在该节点的局部特征函数的总数。

                                                    

        第二类是定义在Y节点yi上的状态特征函数s,这类特征函数只和当前节点有关特征函数式子如下所示。其中, K2是定义在该节点的局部特特征函数的总数。

                                                     

        需要注意的是两类特征函数是通过人为定义的。特征函数的输出值是0或1,0表示要标注序列不符合这个特征,1表示要标注序列符合这个特征。 假设 x=“我去广州旅游”,标注的状态集合为 S={B,I,O},分别代表命名实体的开始、实体中间、其他。状态特征函数s和转移特征函数t可以定义为如下形式.

        

        特征函数不限于上述的定义,还可以定义很多。直观上,上述特征函数t1比t3在语料库中出现的可能性更大,理应拥有更大的权重。同理,可以为每个特征函数赋予一个权值,用以表达这个特征函数的重要性。 构建完特征函数,即可仿照多项逻辑斯谛回归模型定义linear-CRF的条件概率分布p(Y|X)。设p(Y|X)为linear-CRF,随机变量X取值为x的条件下,随机变量Y取值为y的条件概率分布的定义如下式子所示。

                                

        在上述式子中,Z(x)的定义如下所示。

                ​​​​​​​        ​​​​​​​        

         在Z(x)的式子中, t_k(y_{i-1}, y_i, x, i), \quad t_k(y_{i-1}, y_i, x, i)称为转移特征函数和状态特征函数,特征函数tk和sl取值为1或0。当满足特征条件时取值为1,否则为0。𝜆k和𝜇k分别是转移函数和状态函数的权重。

2.3特征函数简化形式

        为了便于描述特征函数,我们将两类特征函数表示为如下式子。

        ​​​​​​​        ​​​​​​​        

         对转移与状态特征在各个位置i 求和,如下式子所示。

        ​​​​​​​        ​​​​​​​                

         用 ω_k表示特征fk (x,y)的权值,如下式子所示。

                        ​​​​​​​        ​​​​​​​   

        随机变量Y取值为y的条件概率分布的定义式子可以表示为如下式子所示。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​    

         Z(x)式子可以表示为如下式子所示。其中, K=K1+K2。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​     

         进一步,若用F(x, y) = \left(\begin{array}{c} f_1(x, y) \\ f_2(x, y) \\ \vdots \\ f_k(x, y) \end{array}\right) 表示全局特征向量,\omega = \left(\begin{array}{c} \omega_1 \\ \omega_2 \\ \vdots \\ \omega_K \end{array}\right)表示权值向量。上述式子可以表示为内积形式。随机变量Y取值为y的条件概率分布式子的内积形式式子可表示为如下式子所示。

                ​​​​​​​        ​​​​​​​             

        Z(x)式子的内积形式式子可进一步表示为如下式子所示。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

2.4条件随机场的参数估计问题

        随机变量Y取值为y的条件概率分布内积形式的式子和上文式子中,参数𝜔是未知的,linear-CRF模型参数需要通过训练数据进行估计。

         假定对于训练数据有一组样本集D = \{ x_j \mid y_j \}_{j=1}^{N},其中的样本之间是相互独立的, p ̂ (x,y)为训练样本中(x,y)的经验概率。对于条件概率模型p_{w}( y|x) ,训练数据样本集D的对数似然函数如下式子所示。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        

        由随机变量Y取值为y的条件概率分布式子和Z(x)式子可得如下式子。在式子中,\omega = \left(\begin{array}{c} \omega_1 \\ \omega_2 \\ \vdots \\ \omega_K \end{array}\right)是需要估计的权重参数。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​ 

        已知训练数据集D ,由此可知经验概率分布p ̂(x,y)。 可以通过极大化训练数据的对数似然函数求模型参数。 具体的优化算法有改进的迭代尺度法、梯度下降法以及拟牛顿法。有兴趣的读者可以看下文学习。

最优化方法——梯度下降法、牛顿法、LM算法_最优化理论的三大经典算法-CSDN博客

2.5条件随机场的预测问题

        预测问题就是给定条件随机场p(Y|X)和输入序列x(观测序列),求条件概率最大的输出序列y(标记序列),如下式子所示。

                                                        

        上述式子可以利用动态优化的算法求解,常用的求解方法有Viterb动态优化的方法。有兴趣读者可以看下文学习。

        Viterbi-Algorithm(维特比算法)_viterbi algorithm-CSDN博客

3.中文命名实体识别

        CRFsuite基于C/C++实现了条件随机场模型,可用于快速训练和序列标注。 sklearn-crfsuite库是基于CRFsuite库的一款轻量级的CRF库,提供了条件随机场的训练、预测和评测方法。该库可兼容sklearn算法,因此可以结合sklearn库的算法设计命名实体识别系统。

        中文命名实体识别主要使用sklearn-crfsuite库进行的,其流程中的步骤包括文本预处理(语料预处理、语料初始化、训练数据),模型训练与预测(模型训练、模型预测)。其中将实现文本预处理步骤的代码定义为CorpusProcess类,模型训练与预测步骤的代码定义为CRF_NER类。

        CorpusProcess类主要实现内容包括语料读取与写入、语料预处理(全角转半角、连接姓名、合并中大粒度分词与时间)、语料初始化(初始化字序列、词性序列、标记序列)、训练数据(窗口统一切分、特征提取)。 CRF_NER类主要实现的内容包括语料预处理执行、模型定义、模型训练与保存、模型预测。

3.1下载sklearn-crfsuite库

conda activate nlp  #打开虚拟环境
conda install -c conda-forge sklearn-crfsuite #下载sklearn-crfsuite库

3.2 CorpusProcess类框架

代码示例:

import joblib # 导入 joblib 库,通常用于模型的持久化和反序列化。
import sklearn_crfsuite  # 导入 sklearn-crfsuite 库,用于构建和使用条件随机场模型。

class  CorpusProcess(object):
    #由词性提取标签
    def pos_to_tsg(self,p):
        t =self._maps.get(p, None) # 使用字典的 get 方法尝试获取词性 p 对应的标签。
        return t if t else 'o'  # 如果找到了对应的标签则返回,否则返回默认标签 'o'。

    #标签使用SIO模式
    def tag_perform(self,tag,index):
        if index==0 and tag!='o': # 如果是序列的第一个元素且标签不是 'o'
            return 'B_{}'.format(tag)   # 格式化为实体开始的标签。
        elif tag!='o': # 如果标签不是 'o'(即标签表示实体的一部分)
            return 'I_{}'.format(tag) # 格式化为实体内部的标签。
        else:   # 如果标签是 'o'(即标签表示非实体)
            return tag    # 直接返回标签 'o'。

    #全角转半角
    def q_to_b(self,q_str):
        b_str = ''   # 初始化半角字符串变量为空字符串
        for uchar in q_str: # 遍历全角字符串中的每个字符
            inside_code=ord(uchar)  # 获取当前字符的 Unicode 编码
            if inside_code==12288: #全角空格转换,如果当前字符是全角空格(Unicode 编码为 12288)
                inside_code=32 # 转换为半角空格的 Unicode 编码
            elif 65374 >=inside_code>=65281: #全角字符(除空格)根据关系转化 检查当前字符是否是全角字符(除空格)
                inside_code -= 65248 # 根据 Unicode 编码转换规则,将全角字符转换为半角字符
            b_str+=chr(inside_code) # 将转换后的半角字符追加到半角字符串变量
        return b_str # 返回转换后的半角字符串

    #语料初始化
    def initialize(self):
        # 从文件中读取语料数据,使用 process_corpus_path 属性指定的路径。
        lines=self.read_corpus_from_file(self.process_corpus_path)
        # 使用列表推导式处理每一行数据:
        # 1. 使用 strip() 方法去除每行字符串的首尾空白字符。
        # 2. 使用 split() 方法按空格分割处理后的行,得到单词列表。
        # 3. 过滤掉空字符串,确保只处理非空行。
        words_list=[line.strip().split(' ') for line in lines if line.strip()]
        # 删除不再使用的 lines 列表,以释放内存空间。
        del lines
        # 初始化序列,将处理后的单词列表转换为模型训练所需的格式。
        # 这里假设 init_sequence 是一个已经定义好的方法,用于进一步处理单词列表。
        self.init_sequence(words_list)

    # 初始化字序列,词序列
    def init_sequence(self, words_list):
        # 初始化单词序列,从每个单词/词性对中提取单词
        words_seq=[[word.split('/')[0] for word in words]for words in words_list]
        # 初始化词性序列,从每个单词/词性对中提取词性
        pos_seq=[[word.split('/')[1] for word in words]for words in words_list]
        # 初始化标签序列,为每个词性调用 pos_to_tag 方法转换为标签
        tag_seq=[[self.pos_to_tag(p) for p in pos] for pos in pos_seq]
        # 应用 tag_perform 方法,假设它接受一个标签和对应的单词索引
        # 这里假设每个标签与 words_seq 中的单词一一对应
        self.tag_seq = [[[self.tag_perform(tag_seq[index][i],w)
                          for w in range(len(words_seq[index][i]))]
                             for i in range(len(tag_seq[index]))]
                                for index in range(len(tag_seq))]
        # 扁平化标签序列,将嵌套的列表结构变为一个列表
        self.tag_seq=[[t for tag in tag_seq for t in tag]for tag_seq in self.tag_seq]
        # 初始化单词序列,为每个序列添加开始(BOS)和结束(EOS)标记
        # 这里假设每个句子由空格分隔的单词组成
        self.words_seq = [['<BOS>']+[w for word in word_seq for w in word]+['<EOS>'] for word_seq in words_seq]


    #窗口同一切分
    def seqment_by_window(self, words_list=None, window=3):
        # 定义一个方法 seqment_by_window,它可能是 segment_by_window 的拼写错误。
        # self 表示这个方法是类的实例方法。
        # words_list 参数接收一个包含单词的列表,None 表示可以不提供该参数。
        # window 参数指定了窗口大小,默认值为 3。
        words=[]  # 初始化一个空列表 words,用于存储通过窗口划分得到的单词序列。
        begin,end =0,window
        # 初始化两个变量 begin 和 end,分别表示窗口的起始和结束索引。
        # begin 起始索引设置为 0,end 结束索引设置为 window,即窗口大小。
        for _ in range(1,len(words_list)):
            # 开始一个 for 循环,循环变量用 _ 表示,从 1 开始到 words_list 的长度(不包括)。
            # 这里从 1 开始循环意味着会跳过 words_list 的第一个元素。
            if end>=len(words_list):
                break
            # 如果窗口的结束索引 end 超过了 words_list 的长度,跳出循环。
            words.append(words_list[begin:end])
            # 将 words_list 中从 begin 到 end(不包括 end)的子列表添加到 words 列表中。
            begin=begin+1
            end=end+1
            # 将窗口的起始索引 begin,end 向前移动一位。
        return words   # 返回存储了窗口划分结果的 words 列表。


    #特征提取
    def extract_features(self, word_games):
        # 定义一个实例方法 extract_features,它接收参数 word_games。
        features=[]
        feature_list=[]
        # 初始化一个空列表 features,用于存储所有句子的所有特征。
        # 初始化一个空列表 feature_list,用于存储单个句子的特征列表。
        for index in range(len(word_games)):
            # 遍历 word_games 中的每个句子,index 是句子的索引。
            for i in range(len(word_games[index])):
                # 遍历句子中的每个元素,i 是元素的索引。
                word_game=word_games[index][i]
                # word_game 是当前句子中的一个三元组,包含当前词及其前后词。
                feature={'w-1':word_game[0],
                    'w':word_game[1],'w+1':word_game[2],
                         # 定义特征字典,包含当前词(w)的前一个词(w-1)和后一个词(w+1)。
                         'w-1:w':word_game[0]+word_game[1],
                         # 组合特征,当前词的前一个词和当前词的拼接。
                            'w:w+1':word_game[1]+word_game[2],
                         # 组合特征,当前词和当前词的后一个词的拼接。
                         'blas':1.0
                         # 添加一个偏置特征,通常用于模型中的常数项。
                }
                # 将 feature 字典添加到 feature_list 中
                feature_list.append(feature)
                # 将当前的 feature_list 添加到 features 中。
                # 这里可能是代码逻辑错误,因为每次循环都将同一个 feature_list 添加多次。
                features.append(feature_list)
        return features  # 返回 features 列表,它包含了 word_games 中所有句子的所有特征。

    #训练数据
    def generator(self):
        # 定义一个名为 generator 的实例方法,用于生成特征和单词序列。
        word_games=[self.seqment_by_window(word_list) for word_list in self.word_seq]
        # 通过列表推导式和 seqment_by_window 方法处理 self.word_seq 中的每个 word_list。
        # self.word_seq 应该是包含多个单词列表的列表,每个 word_list 代表一个句子或序列。
        # self.seqment_by_window 方法将每个句子分割成多个窗口,存储在 word_games 列表中。
        features=self.extract_features(word_games)
        # 调用 extract_features 方法提取 word_games 中的特征。
        # 这可能会为每个窗口生成一组特征,具体取决于 extract_features 方法的实现。
        return features,self.words_seq
    # 返回两个对象:features(特征集合)和 self.words_seq(单词序列)。
    # self.words_seq 应该是与 self.word_seq 相关的单词序列,可能包含开始和结束标记。


        3.3 CRF_NER类的框架

代码示例如下:

import pickle
import joblib # 导入 joblib 库,通常用于模型的持久化和反序列化。
import sklearn_crfsuite  # 导入 sklearn-crfsuite 库,用于构建和使用条件随机场模型。
from sklearn_crfsuite import metrics


class CNF_NET(object):
    def __init__(self):
        self.algorithm ='lbfgs'
        self.c1='0.1'
        self.c2='0.1'
        self.max_iterations=100   #迭代次数
        self.model_path='model.pkl'
        self.corpus=CorpusProcess() #加载文本预处理模块
        self.model=None

    #定义模型
    def initialize_model(self):
        self.corpus.initialize() #初始化语料
        algorithm=self.algorithm
        c1=float(self.c1)
        c2=float(self.c2)
        max_iterations=int(self.max_iterations)
        self.model=sklearn_crfsuite.CRF(algorithm=algorithm,c1=c1,c2=c2,max_iterations=max_iterations,
                                        all_possible_transitions=True)

    #模型训练
    def train(self):
        self.initialize_model()
        x,y=self.corpus.generator()
        x_train,y_train=x[500:],y[500:]
        x_test,y_test=x[:500],y[:500]
        self.model.fit(x_train,y_train)
        labels=list(self.model.classes_)
        labels.remove('O')
        y_predict=self.model.predict(x_test)
        metrics.flat_f1_score(y_test,y_predict,average='weighted',labels=labels)
        sorted_labels=sorted(labels,key=lambda name:(name[1:],name[0]))
        print(metrics.flat_classification_report(y_test,y_predict,labels=sorted_labels,digits=3))
        #保存模型
        joblib.dump(self.model, self.model_path)

    def predict(self, sentence):
        # 加载模型
        try:
            # 加载模型
            with open(self.model_path, 'rb') as f:
                self.model = pickle.load(f)
        except EOFError as e:
            print(f"Error loading model: {e}")
            # 这里可以添加更多的错误处理逻辑
            return None
        u_sent = self.corpus.q_to_b(sentence)
        word_lists = [['<BOS>'] + [c for c in u_sent] + ['<EOS>']]
        word_games = [self.corpus.segment_by_window(word_list) for word_list in word_lists]
        features = self.corpus.extract_features(word_games)
        y_predict = self.model.predict(features)
        entity = ''
        for index in range(len(y_predict[0])):
            if y_predict[0][index] == 'O':
                if index >= 0 and (y_predict[0][index][-1] != y_predict[0][index - 1][-1]):
                    entity += ''
                entity += u_sent[index]
            elif entity[-1] != ' ':
                entity += ''
        return entity

     示例

ner=CNF_NET()
print(ner.predict(u'新华社北京十二月三十一日电(中央人民广播电台记者刘振英、新华社记者张宿堂)今天是一九九七年的最后一天。'))
# '新华社 北京 十二月三十一日  中央人民广播电台  刘振英  新华社  张宿堂  今天  一九九七年 '
 
print(ner.predict(u'一九四九年,国庆节,毛泽东同志在天安门城楼上宣布中国共产党从此站起来了!'))
# '一九四九年  国庆节  毛泽东  天安门城  中国共产党 '

4.命名实体识别流程

4.1 语料预处理

       使用的数据来源于1998年人民日报分词数据集,该数据集中的所有词已经标注了词性,其中部分数据集示例如下图所示。

        由于语料中存在格式不统一字符、姓氏与名字分为两个词语等问题,需要对语料进行统一格式化处理,主要包括以下4个内容。 将语料全角字符统一转为半角。 处理姓名,将姓和名链接在一起。如:江/nr 泽民/nr。 处理合并语料库中括号中的大粒度词。如:[人民/n  大会堂/n]ns。 处理合并语料库中分开标注的时间。如:12月/t  31日/t。

4.2 语料初始化

        语料初始化包括初始化字序列、词性序列,主要是对语料中的句子、词性、实体分类标记进行区分。 由词性提取标签。将语料中的时间、人名、组织机构名和地名分别转化为T、PER、ORG和LOC。 标签使用BIO模式。本次语料的标签采用“BIO”模式,即实体的第一个字为B_*,其余字为I_*,非 实体字统一标记为O。 此外由于模型采用tri-gram形式,在字符列中,需要在句子前后加上占位符(BOS/EOS)。

4.3 训练数据

        训练数据是将经过数据处理后的语料切分为整齐序列并提取相应的特征。 窗口切分。将每个特征序按统一的大小切分成整齐序列。 特征提取。抽取文本中的字符组合或具有其他意义的标记组成特征,作为特征函数的参数;并通过一组 函数完成由特征向数值转换的过程,使特征和一个权值对应。

4.4 模型训练

        模型训练由初始化模型参数、数据预处理及模型定义、模型训练3个部分组成。 初始化模型参数。定义优化算法、迭代次数及基本模型参数。其中优化算法选用了无约束优化算法L-BFGS, 该算法是解无约束非线性规划问题最常用的方法,具有收敛速度快、内存开销少等优点。 数据预处理及模型定义。执行数据预处理模块并定义模型。 模型训练。划分数据前500行数据为训练集、其余作为测试集,接着进行模型训练,最后将模型结果保存。

4.5 模型评价

        模型训练过程中,通过精确率precision(P)、召回率recall(R)和f1-score(F值)3项指标评测中文命名实体识别的识别性能及效果。

        精确率precision(P)公式如下式所示。

                                         

         召回率recall(R)公式如下式所示。 

                                       

         f1-score(F值)公式如下式所示。

                                        

         在上述的3个公式中, P表示识别出的命名实体中出现在测试结果中的比例,R 表示标准结果中被正确识别出的命名实体的比例, Nc表示正确找出的命名实体数, Nd表示测试结果中的所有命名实体数, Nt表示测试集中实际命名实体数。

        模型训练过程中输出测评指标如下图所示。 在下图中,LOC、ORG、PER、T分别表示地点、组织机构、人名、时间,precision、recall、f1-score、support则为对应的准确率、召回率、F1值和参与训练样本数。 从测评指标结果看,总训练样本5955个,平均预测准确率0.953,平均召回率0.904,平均F1值0.928,总体模型训练效果较好。

                                

4.6 模型预测

        模型预测需要先对待预测语料进行数据预处理,然后加载训练完成的模型进行预测,输出语料中存在的命名实体。 输入下面两个句子,使用训练好的模型进行预测。

         “2019年10月1日是一个重要日子,在陕西、江西、广东,村委会服务中心集纳了百姓所需的各类服务:有的干部组织开展农技指导工作,让农产品越种越好;有的商店成为生活驿站,养老金领取、银行存取款、快递包裹寄'\取、电商代销代购等都能在这“一站式”解决;有的重点关注老人和儿童,让他'们活动有去处、有事做,为生活增添色彩。”。

        “1995年,君乐宝乳业集团总裁魏立华创办君乐宝酸奶。凭着对产品质量的孜孜追求,君乐宝乳业迅速成长,2012年销售额达到20亿元。

        根据上页输入的句子,模型输出结果如下图所示。

​​​​​​​                                          

         从输出结果可以看出,模型能正确将第一条语料中的时间、地点识别并输出;第二条语料中的时间、公司名称、人名等命名实体能被完全识别并输出,效果最佳;总体上看,该模型的命名实体识别效果较好。 对于第一条语料中只有部分命名实体被识别输出,是因为该语料语句较为复杂,更难被识别出。对于这种情况,可以通过丰富训练数据语料库、增加训练次数等方式优化模型,以达到提高模型识别准确率的目的.

        

  • 22
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值