• NLP相关



    NLP相关算法,HMM、CRF、TFIDF、TextRank、pagerank、LDA、word2vec、Doc2Vec、TextCNN、Bi-LSTM+CRF、Lattice-LSTM、transformer、BERT等

    base

    分词、词性标注、实体识别

    常见的分词算法有:基于字符串匹配的分词方法、基于理解的分词方法、基于统计的分词方法和基于规则的分词方法

    词性标注,就是给每个词或者词语打词类标签,如形容词、动词、名词等。这样做可以让文本在后面的处理中融入更多有用的语言信息。
    词性标注是一个经典的序列标注问题,不过对于有些中文自然语言处理来说,词性标注不是非必需的。
    比如,常见的文本分类就不用关心词性问题,但是类似情感分析、知识推理却是需要的

    .

    命名实体识别NER(Named Entities Recognition)是自然语言处理NLP的一个基础任务,其目的是识别语料中人名、地名、组织机构名等命名实体
    有两个主流方法
    1、基于规则和词典
    基于规则的方法多采用专家手工构造规则模板、选用特征,包括统计信息、标点符号、关键字、指示词和方向词、位置词(如尾字)、中心词等方法,以模式和字符串匹配的手段,这类系统大多依赖于规则和词典的建立
    基于规则和词典的方法是NER中一般使用的方法,【一般当提取的规则能比较精确地反映语言现象时,基于规则的方法性能要优于基于统计的方法】
    但是这些规则往往依赖于具体语言、领域和文本风格,编制过程耗时且【难有泛化性】,系统可移植性不好,对于不同的系统需要专家重新书写规则
    另外一个缺点是代价大,存在系统建设周期长、移植性差而且需要建立不同领域知识库作为辅助以提高系统识别能力等问题

    2、基于统计
    方法主要包括:隐马尔可夫模型(HiddenMarkovMode,HMM、最大熵(MaxmiumEntropy,ME)、支持向量机(Support VectorMachine,SVM)、条件随机场( ConditionalRandom Fields,CRF)等
    ME具有较好的通用性,但缺点是训练时间复杂性非常高,导致训练代价难以承受
    HMM更适用于一些对实时性有要求并且需要处理大量文本的应用,如短文本命名实体识别

    .

    预处理去除停用词(a an the it 的 是)、去标点、排除乱码、统一一些代替词、词典添加专业词等

    判断字符符号英语乱码
    
    def iszh(x):  # 判断字符串有没有中文,也能判断字符是不是中文
        for c in x:
            # if ord(c) > 255:
            if '\u4e00' <= c <= '\u9fa5':  # 是不是中文
                return True
        return False
    
    def ispun(char):  # 判断标点
        for i in char:
            if re.match(r"[^a-zA-Z0-9\u4e00-\u9fa5]",i):
                return True
        return False
    
    def isus(char):  # 判断英文和数字
        for i in char:
            if (i >= '\u0041' and i <= '\u005a') or (i >= '\u0061' and i <= '\u007a'):  # 英文
                return True
            elif i >= '\u0030' and i <= '\u0039':  # 数字
                    return True
        return False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    ·jieba中文分词
    jieba主要的模块如下
    ·基本API的封装,在Tokenizer类中,相当于一个外观类。如cut del_word add_word enable_parallel initialize 等
    ·基于字符串匹配的分词算法,包含一个很大很全的词典,即dict.txt文件
    ·基于统计的分词算法,实现了HMM隐马尔科夫模型。jieba分词使用了字符串分词和统计分词,结合了二者的优缺点。
    ·关键词提取,实现了TFIDF和TextRank两种无监督学习算法
    ·词性标注,实现了HMM隐马尔科夫模型和viterbi算法(离散随机过程的概率统计,然后Viterbi动态规划算法找出最优)

    可以延迟加载,import时不会立即加载,使用时才加载
    import jieba
    jieba.initialize() # 手动初始化(可选)
    (适合用于判断中英文后再决定调不调用)

    三种分词
    # encoding=utf-8
    import jieba
    
    seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
    print( "/ ".join(seg_list))  # 全模式,一般不用/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
    
    seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
    print( "/ ".join(seg_list))  # 不指定cut_all默认是精确模式,一般用它/ 来到/ 北京/ 清华大学
    他, 来到,, 网易, 杭研, 大厦    (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)
    
    seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造")  # 搜索引擎模式
    print(", ".join(seg_list))
    小明, 硕士, 毕业,, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所,,, 日本, 京都, 大学, 日本京都大学, 深造
    
    
    词性标注
    import jieba.posseg as pseg
    words = pseg.cut(q1)
    我 r 代词,爱 v 动词,北京 ns 名词,天安门 ns 名词
    
    
    def jiebatfidf():
        # tfidf,关键词提取
        import jieba.analyse  # 这里实现了tfidf和textrank
        text = '关键词是能够表达文档中心内容的词语,常用于计算机系统标引论文内容特征'
        keywords = jieba.analyse.extract_tags(text, topK=10, withWeight=False, allowPOS=())
        print(keywords)   # ['标引', '内容', '文档', '计算机系统', '词语', '关键词', '论文', '表达', '常用', '特征']
    jiebatfidf()
    
    
    
    调整词典
    # 1 使用del_word()使得某个词语不会出现
    print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
    # 如果/放到/post/中将/出错/。
    jieba.del_word("中将")
    print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
    # 如果/放到/post/中/将/出错/。
    
    # 2 使用add_word()添加新词到字典中
    print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))
    # 「/台/中/」/正确/应该/不会/被/切开
    jieba.add_word("台中")
    print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))
    # 「/台中/」/正确/应该/不会/被/切开
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    NLTK英文分词
    from nltk.tokenize import word_tokenize
    from nltk.corpus import stopwords
    word_tokens = word_tokenize(x)  # 英文分词,底层是基于正则
    stop_words = set(stopwords.words('english')) 
    filtered_sentence = [w for w in word_tokens if not w in stop_words] # del and if it ... 去停用词
    print(filtered_sentence)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    HMM

    隐马尔可夫模型(Hidden Markov Model,HMM)
    隐马尔可夫模型描述由一个隐藏的马尔科夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测而产生观测随机序列的过程。隐马尔可夫模型由初始状态分布,状态转移概率矩阵以及观测概率矩阵所确定。
    命名实体识别本质上可以看成是一种序列标注问题,在使用HMM解决命名实体识别这种序列标注问题的时候,我们所能观测到的是字组成的序列(观测序列),观测不到的是每个字对应的标注(状态序列)。
    HMM模型的训练过程对应马尔可夫模型的学习问题,实际上就是根据训练数据根据最大似然的方法估计模型的三个要素,即上文提到的初始状态分布、状态转移概率矩阵以及观测概率矩阵,模型训练完毕之后,利用模型进行解码,即对给定观测序列,求它对应的状态序列,这里就是对给定的句子,求句子中的每个字对应的标注,针对解码问题,使用维特算法。
    HMM模型中存在两个假设,一是输出观察值之间严格独立,二是状态转移过程中当前状态只与前一状态有关。也就是说,在命名实体识别的场景下,HMM认为观测到的句子中的每个字都是相互独立的,而且当前时刻的标注只与前一时刻的标注相关。但实际上,命名实体识别往往需要更多的特征,比如词性,词的上下文等等,同时当前时刻的标注应该与前一时刻以及后一时刻的标注都相关联。由于这两个假设的存在,显然HMM模型在解决命名实体识别的问题上是存在缺陷的。

    适用于一些对实时性有要求并且需要处理大量文本的应用,如短文本命名实体识别

    CRF

    条件随机场(conditional random field,简称CRF),是一种鉴别式机率模型,是随机场的一种,常用于标注或分析序列资料,如自然语言文字或是生物序列。

    随机过程:
    设T是一无限实数集, 把依赖于参数t∈T的一族(无限多个)随机变量称为随机过程, 记为X(t),t∈T

    随机场:
    从平面(随机过程)到向量空间(随机场)
    若T是n维空间的某个子集, 即t是一个n维向量, 此时随机过程又称为随机场. 常见随机场有: 马尔可夫随机场(MRF), 吉布斯随机场(GRF), 条件随机场(CRF)和高斯随机场.

    条件随机场:
    设X与Y是随机变量, P(Y∣X)是在给定X的条件下Y的条件概率分布.
    若随机变量Y YY构成一个由无向图G=(V,E)表示的马尔可夫随机场, 即
    P(Yv|X, Yw) = P(Yv|X, Yw, w~v)
    对任意顶点v成立, 则称条件概率分布P(Y∣X)为条件随机场.

    只基于Y序列做预测, 太单调了, 所以额外给出一个观测序列X, 帮助你更好的做决策. 这就是从马尔可夫随机场变成条件随机场的过程. 条件随机场中, "条件"指的是给定观测序列X的情况, 求状态序列Y的概率, 即输出的是条件概率分布. 而"随机场"指的是状态序列Y构成的随机场.

    根据Hammersley Clifford定理, 一个无向图模型的概率, 可以表示为定义在图上所有最大团上的势函数的乘积.
    那么, CRF的条件概率可以在因子分解下表示为:
    在这里插入图片描述

    TFIDF

    TF-IDF(term frequency–inverse document frequency,词频-逆向文件频率)是一种用于信息检索(information retrieval)与文本挖掘(text mining)的常用加权技术。
    TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
    它的主要思想是:如果某个单词在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分能力,适合用来分类。

    TF-IDF是一种很简单但却很有效的方法,计算文本中的每个term会考虑两个因素。一是term本身在文档中的词频,这就是上小结提到的TF,另一个是倒文本频率(Inverse Document Frequency)IDF,这个指标衡量的是有多少文本包含了该term。IDF主要用来惩罚那些在很多文本中都有出现的term,往往这些term都是一些无关紧要的停用词等。

    词频TF,是一个词在一个文中出现的频率,count/len(text),除以len就是归一化了,防止偏向长文件
    逆文档频率IDF,词语重要性的度量,lg(总文件数/包含该词语的文件数目)

    TF-IDF常应用于搜索引擎、关键词提取、文本相似性、文本摘要

    PageRank

    PageRank文本重要性算法——Google的网页排名算法
    PageRank算法通过计算网页链接的数量和质量来粗略估计网页的重要性,算法创立之初即应用在谷歌的搜索引擎中,对网页进行排名。
    PageRank对于每个网页页面都给出一个正实数,表示网页的重要程度,PageRank值越高,表示网页越重要,在互联网搜索的排序中越可能被排在前面。

    网页重要性评价值,是依据指向该网页的所有其他网页的重要性,以及这些网页中包含的链接数求得的
    由于每次计算时都需要关联其他网页,所以开始时会给每个网页一个任意的初始值
    迭代多次,每个网页的PageRank值将会越来越接近真实值
    在这里插入图片描述
    计算每个节点的公式如下:
    在这里插入图片描述
    其中S(Vi)表示网页i的权重分值,In(Vi)表示指向节点Vi的节点,Out(Vj)表示节点Vj指出的节点。Out(Vj)表示节点Vj指出节点的总数。为了保证PageRank(或者随机游走)不会死循环到一个环出不来,增加了一个随机因子α,α表示不进行随机跳转的概率

    # -*-coding:utf8 -*-
    import sys
    import numpy as np 
    
    
    def pagerank(graph):
    	'''
    		简单实现pagerank迭代过程
    	'''
    	pr = np.array([1, 1, 1, 1]) #init node
    	a = 0.85   
    	for iter in range(10):
    		pr = (1-d) + d * np.dot(graph, pr)
    		print(iter)
    		print(pr)
    
    
    if __name__=='__main__':
    	graph = np.array([[0,0,0,0],
    					  [0,0,0,0],
    					  [1, 0.5, 0, 0],
    					  [0,0.5,0,0]])
    	pagerank(graph)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    TextRank

    textrank通过词之间的相邻关系构建网络,然后用PageRank迭代计算每个节点的rank值,排序rank值即可得到关键词,可以实现关键词提取、关键词短语提取、计算相似度选择文本摘要,一般用于摘要提取

    最原始的PageRank算法是无权重的图,而TextRank是有权重的图。因此,节点的权重分值计算和PageRank比变动如下:
    在这里插入图片描述
    其中wij表示了节点Vj与节点Vj之间的边连接权重

    TextRank算法的步骤:
    预处理:文本分词,然后用标注工具进行标注,获取重要的词性
    构建图:将处理后的词作为图的节点,边根据这些词是否在一个滑动窗口共现,进行边的连接。初始各节点权重都为1,然后用上述计算公式进行迭代
    计算分值:所有unigrams(节点)权重分值计算完后,选取top个节点,再根据设置的窗口大小,计算更高的n-gram关键词分值,最后根据分值,获取top K个关键词

    TextRank与TFIDF均严重依赖于分词结果。是否添加标注关键词进自定义词典将会造成准确率、召回率大相径庭
    TextRank的效果并不优于TFIDF
    TextRank虽然考虑到了词之间的关系,但是仍然倾向于将频繁词作为关键词
    一个缺点是这两种方法本质上还是基于词频衡量一个词的重要性,所以准确率并不高

    LDA

    隐含狄利克雷分布(Latent Dirichlet Allocation,LDA),是一种主题模型(topic model),它可以将文档集中每篇文档的主题按照概率分布的形式给出。
    LDA潜在狄利克雷分布是模型,非监督机器学习。它认为一篇文档是有多个主题的,而每个主题又对应着不同的词,LDA假定文章中的词与词之间互相独立,而HMM中是所有的观测互相均不独立
    其实不如用HMM,其实不独立才对

    word2vec

    Word2Vec之类的模型,准确来说应该是“自监督”的,它事实上训练了一个语言模型,通过语言模型来获取词向量。
    所谓语言模型,就是通过前个字预测下一个字的概率,就是一个多分类器而已,我们输入one hot,然后连接一个全连接层,然后再连接若干个层,最后接一个softmax分类器,就可以得到语言模型了,然后将大批量文本输入训练就行了,最后得到第一个全连接层的参数,就是字、词向量表,当然,Word2Vec还做了大量的简化,但是那都是在语言模型本身做的简化,它的第一层还是全连接层,全连接层的参数就是字、词向量表。

    word2vec主要包含 跳字模型Skip-Gram和连续词袋模型CBOW(Continuous Bag of Words)
    它可以可以较好地表达不同词之间的相似和类比关系
    CBOW是根据上下文的词汇去预测中间词来学习词向量的,而Skip-gram正好相反,它是通过给定中间词去预测上下文词来学习词向量的,都是单隐层的网络结构
    word2vec通过捕获当前词的上下文信息,可以将相近的词映射到向量空间中的相近位置,并训练得到词向量表示。在模型训练时,对输入的句子序列通过查询该词向量表,将离散的符号化的单词转化为对应的词向量序列,并将得到的词向量表示作为当前航行通告句子序列词级别的特征
    输出层是一个全连接的softmax结构(超大规模n分类问题),缺点在于softmax计算成本非常大(onehot向量维度为词典维度),计算耗时

    (超大规模n分类问题计算成本非常大 onehot向量维度为词典维度,计算耗时,有些任务用它必要性不大)

    other

    Bi-LSTM+CRF
    基于双向LSTM的序列标注模型Bi-LSTM+CRF
    双向循环神经网络(BiRNN) + 条件随机场(CRF)
    LSTM的优点是能够通过双向的设置学习到观测序列(输入的字)之间的依赖,在训练过程中,LSTM能够根据目标(比如识别实体)自动提取观测序列的特征,但是缺点是无法学习到状态序列(输出的标注)之间的关系,要知道,在命名实体识别任务中,标注之间是有一定的关系的,比如B类标注(表示某实体的开头)后面不会再接一个B类标注,所以LSTM在解决NER这类序列标注任务时,虽然可以省去很繁杂的特征工程,但是也存在无法学习到标注上下文的缺点。
    相反,CRF的优点就是能对隐含状态建模,学习状态序列的特点,但它的缺点是需要手动提取序列特征。所以一般的做法是,在LSTM后面再加一层CRF,以获得两者的优点。

    transformer模型
    用全attention的结构代替了seq2seq里的lstm,一般用于机器翻译

    BERT使用了使用的是transformer的encoder部分,它是mask语言模型,随机mask掉15%的词,然后训练,等价于交叉熵损失函数,这样的Transformer在编码一个词的时候就会参考上下文的信息
    用attention层自动学习文本中的每个词的权重,根据词的权重,可以获取与文本主题相关的关键词
    模型里还包含一个二分类任务,用来预测两个句子是否连接在一起
    (用于文本分类,参数太多)


    关系规则提取对象
    在这里插入图片描述
    词性标注提取
    在这里插入图片描述

  • 相关阅读:
    浮点数在内存中的存储
    OpenCV自学笔记十一:形态学操作(一)
    黄金票据和白银票据
    shell [stdin/stdout/stderr][重定向]
    Vulkan与OpenGL对比——Vulkan的全新渲染架构
    【低代码】角色和权限的解决方案
    理解STM32的低功耗模式
    《深入浅出WPF》——资源学习
    JavaWeb开发之——JavaWeb介绍(01)
    vue封装自己的组件库 02.封装dialog组件
  • 原文地址:https://blog.csdn.net/weixin_42394432/article/details/125550192