NLP-基础知识-001

一、文本分析流程

 Pipeline

原始文本(网页文本、新闻、...) ->  分词(中文、英文) -> 清洗(无用的标签 !¥ 停用词.....)  -> 标准化(英文时态等) -> 特征提取(tf-idf、word2vec) -> 建模(分类算法、相似度算法) -> 评估过程

二、分词工具

英文没有分词、中文主要以下工具进行分词

jieba分词      https://github.com/fxsjy/jieba

SnowNLP    https://github.com/isnowfy/snownlp

HanNLP      https://github.com/hankcs/HanLP

分词方法:

(一)最大匹配(Max Matching)

  前向最大匹配(forward-max matching)

  例子: 我们经常有意见分歧(输入) max-len = 5

  词典: ["我们","经常","有","有意见","意见","分歧"]

  流程:

       1、【我们经常有】意见分歧  未在词典

            【我们经常】有意见分歧

            【我们经】常有意见分歧

            【我们】经常有意见分歧  【我们】在词典中

       2、【经常有意见】-》【经常有意】见 -》【经常有】意见 -> 【经常】有意见

       3、【有意见分歧】-》【有意见分】歧 -》 【有意见】分歧 

       4、【分歧】

      分词结果:我们 | 经常 | 有意见 | 分歧

      贪心算法-局部最优   动态规划-全局最优

      max-len 一般设置为5-10 ,或者画图看一下字典里面的词语长度横坐标为词的长度,纵坐标为该词的长度的个数     

(二) 后向最大匹配

     例子: 我们经常有意见分歧

     词典: ["我们","经常","有","有意见","意见","分歧"]

     流程:

      1、[有意见分歧] -> [意见分歧] -> [见分歧] -> [分歧]

      2、[经常有意见] -> [常有意见] -> [有意见]

      3、[我们经常] -> [们经常]  -> [经常]

      4、[我们]

    分词结果: 我们 | 经常 | 有意见 | 分歧

 

    前向匹配和后向匹配结果是一样的(90%)

    最大匹配的缺点:

              1)不能考虑短词语的情况   

              2)  贪心算法-> 局部最优   

              3)   效率比较低 依赖于超参数max-len 

              4)  不能更好地处理歧义的情况(不考虑语义)

(三) 基于语义的分词工具

    例子: 经常有意见分歧

    词典: 【'有',"有意见","意见",”分歧“,"见","意","经常"】

    语言模型

     输入   ---->    step 1 -  生成所有可能的分割 (递归 + 匹配)  ----->   step 2 - 选择其中最好的(语言模型)

    语言模型  - unigram model

     s1: 经常 | 有 | 意见 | 分歧

     s2: 经常 | 有意见 | 分歧

     p(s1) = p(经常) * p(有) * p(意见) * p(分歧)

     p(s2) = p(经常) * p(有意见) * p(分歧)

     p(s1) >= p(s2)

     Underflow:数值超出类型范围的最小值,所以上述概率两边需要同时去对数,避免underflow的情况

     logp(s1) = logp(经常)  + logp(有)  + logp(意见) + log p(分歧)

    p(经常) 、p(有) 、 p(意见) 、 p(分歧) 单词概率会在所有语料中统计得到

   缺点:生成所有分割,可能性太多,效率比较低

(四) 维特比算法

   第一步和第二步融合一下,加快效率    -----    维特比算法

分词小结:

     -  基于匹配规则的方法

     -  基于概率统计的方法(LM,HMM,CRF....)

     -  分词可以认为是已经解决的问题

三、拼写纠错(Spell Correction)

      (一) 识别错别字

            例如:

                      用户输入:   天起   -----> 改正------> 天气

             改正过程具体做法:

             定义三个操作: Add Delete Replace

用户输入候选

编辑距离(Edit Distance)

str1 -> str2

therrthere1
 

thesis

theirs

the

 

词典

2

2

2

 

......

            1) query 单词与词库进行匹配     2)找出编辑距离最小的单词

Alternative Way:

    之前的方法: 用户输入  -->  从词典中寻找编辑距离最小的    -->   返回

    现在的方法: 用户输入  -->  生成编辑距离为1,2的字符串 (Candidate)   ---> 过滤 (filter) ----> 返回

""" 生成编辑距离为1和2的字符串 """

def generate_edit_one(str1):

    """
    给定一个字符串, 生成编辑距离为1的字符串
    """
    letters = 'abcdefghijklmnopqrstuvwxyz'
    splits = [(str1[:i],str1[i:]) for i in range(len(str1) + 1)]
    inserts = [L + c + R for L,R in splits for c in letters]
    deletes = [L + R[1:] for L,R in splits if R]
    replaces = [L + c + R[1:] for L,R in splits if R for c in letters]

    return set(inserts + deletes + replaces)
    
def generate_edit_two(str1):

    """
     给定一个字符串,生成编辑距离小于等于2的字符串
    """

    return [e2 for e1 in generate_edit_one(str1) for e2 in generate_edit_one(e1)]


  过滤:

      问题定义: 给定一个字符串s, 我们要找出最有可能成为正确的字符串c, 也就是c' = argmaxp(c|s)

      简化:c' = argmax p(c|s)     =>    c' = argmax p(s|c) * p(c) / p(s)   (p(s)常数)  =>   c' = argmax  p(s|c) * p(c)

       p(s|c) 、p(c)基于已有词库统计得到

      

      (二) 用错单词(基于上下文语义-语言模型)  

 

四、过滤词(Filtering Words)

    对于NLP应用,我们通常先把停用词、出现频率很低的词汇过滤掉

    不同的应用需要修正停用词库-类似特征筛选的过程

 

五、Stemming算法 英文用的比较多、中文比较少  one way to normalize

    went,go,going

    fly,flies

    deny,denied,denying

    fast,faster,fastest

   不同形态单词归成一个单词

"""应用例子"""

from nltk.stem.porter import *

stemmer = PorterStemmer()

test_strs = ['flies','dies']

singles = [stemmer.stem(word) for word in test_strs]

print(' '.join(singles))

六、文本表示(Word Representation)

 文本表示-(单词表示、句子表示)

one-hot representation

词典:[我们、去、爬山、今天、你们、昨天、跑步]

每个单词的表示:

我们: [1,0,0,0,0,0,0]
爬山: [0,0,1,0,0,0,0]
跑步: [0,0,0,0,0,0,1]
昨天: [0,0,0,0,0,1,0]

句子的表示方法(sentence representation - boolean):

我们 今天 去 爬山: [1,1,1,1,0,0,0]
你们 昨天 跑步: [0,0,0,0,1,1,1]
你们 又 去 爬山 又 去 跑步 : [0,1,1,1,0,1,0,1]

句子的表示方法(sentence representation - count):

你们 又 去 爬山 又 去 跑步 : [0,2,2,1,0,1,0,1]

缺点:1、不考虑单词顺序  2、稀疏矩阵  3、频繁出现无用的词

为了防止某些无用的词频比较大,可以使用log(item+1)


Sentence Similarity

1、计算距离(欧式距离):d = |s1-s2|

    s1 = (1,0,1,1,0,0,0,0) s2 = (0,0,0,0,0,1,1,1) d(s1,s2) = (1^2 + 0^2 + .....)^(1/2)

    欧式距离只考虑大小,不考虑方向,常用的相似度是余弦相似度

2、计算相似度(余弦相似度):sim = s1*s2/*(|s1|*|s2|)

   
总结:词出现的越多并不一定是越重要,并不是出现的越少越不重要

解决办法:不仅需要考虑词,还需要考虑词的权重

Tf-idf Representation

tfidf(w) = tf(d,w)*idf(w)

tf(d,w) -次数 文档d中w的词频  idf(w) =log N/N(w) - 词的重要性

N:语料库中的文档总数
N(w):词语W出现在多少个文档

例子:

文档1: 今天 上 NLP 课程      
文档2:今天 的 课程 有 意思  

文档3:数据 课程 也 有 意思

step 1: 词库的构建

dic = {今天,上,NLP, 课程, 的,有,意思,数据,也}

从词典中看,d2 = (1*log3/2,上没有出现-0,0,1*log3/3,log3/1,log3/2,log3/2,0,0)

七、词向量

语义之间的相似度

我们 爬山 运动 昨天

我们: [0,1,0,0,0,0]
爬山: [0,0,1,0,0,0]
运动: [1,0,0,0,0,0]
昨天: [0,0,0,1,0,0]

1、欧式距离

d(我们,爬山) = d(爬山,运动) = ..... = 2^(1/2)

说明欧式距离相似度针对one-hot不适合做两个词语义之间的相似度的,因为都是2^(1/2)
  
2、余弦距离

d(我们,爬山) = d(我们,运动) = d(运动,爬山) = .... = 0  

说明余弦相似度针对one-hot不适合做两个词语义之间的相似度的,因为都是0

所以如果单词采用one-hot表示,不能表达单词之间的相似度


还存在另一个问题:稀疏性

向量的大小是与词典的大小相同的,如果词典比较大,句子比较短,会出现大量的0


小结:

 onehot不能表示语义之间的相似性,存在稀疏性


从one-hot 表示 到 分布式 表示

One-hot 表示:

我们: [1,0,0,0,0,0,0]
爬山: [0,0,1,0,0,0,0]
运动: [0,0,0,0,0,0,1]
昨天: [0,0,0,0,0,1,0]

分布式表示:

我们: [0.1,0.2,0.4,0.2]
爬山: [0.2,0.3,0.7,0.1]
运动: [0.2,0.3,0.6,0.2]
昨天: [0.5,0.9,0.1,0.3]

one-hot 向量长度是词典长度,分布式向量长度是自己定义的长度,可以为100,200,300,解决了稀疏性问题

针对分布式表示,计算两个词之间的相似度:

d(我们,爬山) = (0.12)^(1/2)

d(运动,爬山) = (0.02)^(1/2)

d(我们,爬山) > d(运动,爬山)


分布式表示方法-针对单词,称为词向量(Word2Vec)

词向量是分布式表示方法的一种

Q1:100维的One-hot表示法最多可以表达多少个不同的单词?  -100个

Q2:100维的分布式表示法最多可以表达多少个不同的单词? -无数个

分布式表示是怎么学习来的?


学习词向量:

输入(Input):字符串(将所有文本的分词之后的单词汇总集合)  -> 深度模型(Skip-Gram、Glove、CBOW、RNN、LSTM、MF-矩阵分解、Gaussian Embedding)训练长短  -> 词的分布式表示  事先需要定义一下词向量维度


词向量(Word2vec)某种意义上理解成词的意思(Meaning)


从词向量到句向量:

"我们去运动"

我们:(0.1,0.2,0.1,0.3)
去:(0.3,0.2,0.15,0.2)
运动:(0.2,0.15,0.4,0.7)

"我们去运动" 句子向量:

   平均法则:
 
   sentence_embedding = avg_embedding = (0.6/3,0.55/3,0.65/3,1.2/3) = (0.2,0.18,0.22,0.4)



八、QA System

How do you like NLP?

     Question             ----> 相似度匹配   ------>  知识库(<Question1,answer1>,<Question2,answer2>.....) 

                         <----  返回相似度比较高的  <------


 存在问题:每个相似度需要计算O(N) 不满足实时的要求

 核心思路:层次过滤思想



    Question          -----> 过滤器  ----> 知识库(<question1,answer1>,<question2,answer2>..) ----> 相似度匹配(<question2,answer2>,<question18,answer18>.....)


 过滤器主要做法--倒排表

 背景:搜索引擎爬取文档

 例如:四个文档

doc_1、我们、今天、运动
doc_2、我们、昨天、运动      -----> 词典:[我们、今天、运动、昨天、上、课、什么] ---> 我们:[doc_1,dic_2],今天:[doc_1],运动:[doc_1,doc_2],昨天:[doc_2] .....
doc_3、你们、上课
doc_4、你们、上、什么、课

如:百度的搜索引擎:

用户输入:运动  如果按照原来的方法需要遍历所有文档,但是按照倒排表只需要遍历doc_1,doc_2,按照pagerank值展示出来相关网页即可

用户输入句子: 我们 课

我们: [doc_1,doc_2]
课:[doc_3,doc_4]

我们 & 上课 = None

直接返回: [doc_1,doc_2,doc_3,doc_4]



"How do you like NLPCamp?"

    Question          -----> 过滤器  ----> 知识库(<question1,answer1>,<question2,answer2>..) ----> 相似度匹配(<question2,answer2>,<question18,answer18>.....)


How do
you like   => 包含这些词的Question(原100,筛选之后可能剩余20, 至少包含其中一个单词) 
MLPCamp


 

 

             

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值