大数据自然语言处理12、NLP

你挡我一时,挡不了我一世

发布日期: 2019-04-12 12:23:32 浏览量: 684
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

前文链接:https://write-bug.com/article/2367.html

文本相似度

一般在讨论相似度时,我们讨论相似度与距离之间的关系:相似度越低,距离越远

我们这里先分为两类:

语义相似:

  • 个人简介

  • 人物介绍

解决方案:协同过滤(用户行为)、回归算法

eg:用户搜索歌神时,大部分人点击张学友,由此两个词间便存在了某种联系

字面相似:

  • 我吃饱饭了

  • 我吃不饱饭

解决方案:LCS最长公共子序列、中文分词(词:token)

eg:通过token列出词粒度集合,通过算法打分或者取交集求取相似度

解决字面相似:

1.cosine余弦相似度

以前在中学学习余弦时都是基于二维坐标系:

  1. cos(θ)=a·b/|a|* |b|

我们词粒度的维度是由token数量决定的,由此我们拓展到n维得:

cos

• 句子A:(1,1,2,1,1,1,0,0,0)

• 句子B:(1,1,1,0,1,1,1,1,1)

计算

a,b即通过分词后得到的词粒度集合向量化

注意:由分词得到的去重集合(BOW bag of word)一旦列举出后顺序不能变

计算流程:

  • 通过TFIDF找出两篇文章的关键词

  • 每篇文章各取出若干个关键词,合并成一个集合,计算每篇文章对于这个集合中的 词的词频

  • 生成两篇文章各自的词频向量

  • 计算两个向量的余弦相似度,值越大就表示越相似

TFIDF:找关键词

1)TF(Term Frequency):词频

即假设如果一个词很重要,那么它在这篇文章中会多次出现。但是,出现最多的不一定是最重要的,比如停用词:“的”“是”“在”。。。(可提前过滤)那么再次假设关键词:在当前文章出现较多,但在其他文章出现少。

公式:

  1. TF1=某词在文章中出现次数 / 文章词总数(基数大) 越大越重要
  2. TF2=某词在文章中出现次数 / 该文章次数最多的词的出现的次数(基数小)

TF越大,越重要

2)IDF:反文档频率,即某一个词在某些文章中出现个数多少的衡量

公式:

  1. log(语库文档总数 / 包含该词的文档数+1) > 0

单调函数,x越大,y越平滑。出现少,分母越小,IDF越大,词越重要。

  1. score= TF*IDF

像停用词这样的词,TF大,IDF小

拓展:自动摘要

1)确定关键词集合

两种方法:

1.score—Top10

2.阈值截断>0.8

2)那些句子包含关键词,取出这些句子

3)对关键词排序,对句子做等级划分(含该关键词的分数线性加和)

4)把等级高的句子取出来,就是摘要

优化:关键词算法、中心思想、第一末尾自然段等等。

tfidf:

  • 优点:简单快速,结果比较符合实际状况

  • 缺点:缺少通顺度,而且关键词不是唯一的权重,比如开头结尾,中心思想。

单纯以“词频”做衡量标准,不够全面,有时重要的词可能出现的次 数并不多

实践:

1.分词

2.数据预处理,把所有文章内容全部收集到一个文件中,每行为一篇文章

  1. convert.py input_tfidf_dir/ >convert.data

3.MR批量计算IDF

  • map.py: word list去重,每一个单词在一篇文章中出现一次计1

  • reduce.py: wordcount + IDF计算

得到token,score集合

排序:cat part-00000 |sort -k2 -nr |head

2.LCS 最长公共子序列:顺序性,不连续

从字面的角度,衡量字面相似度的方法之一

应用:

  • 推荐场景 , item推荐,推荐列表—-保持多样性,满足新鲜感需求,放在推荐引擎中可方便调控相似度阈值过滤(即候选集合后)

  • 辨别抄袭

  • 生物学家常利用该算法进行基因序列比对,以推测序列的结构、功能和演化过程

– 字符串12455与245576的最长公共子序列为2455

– 字符串acdfg与adfc的最长公共子序列为adf

计算方法:

暴力穷举:abc排列组合,取LCS,穷举搜索法时间复杂度O(2^m ∗ 2^n);

动态规划法:

抽象公式:

当xy两字符串最后一位相等时+1,并循环求lcs,不相等时求左右各减一位的最大值,如果有一方为空循环停止,值为0

代码二维数组:

i和j为行和列,从上到下从左到右看,最开始都为空,行列都为0,接着从左到右有相同项左上角+1,不相同的左和上取最大值,最后得出最大序列数

  1. score=4
  2. lenx)=7
  3. leny)=6
  4. simxy)=4*2/6+7=0.615
  5. *2为了归一化

实践:

通过数组维护tokenlist,左右两个字符串按照上面形式计算。

lcs适合粗粒度过滤,适合场景没有cos广泛
因为机器学习中涉及到cos的地方太多了

3.中文分词
中文并不像英文,每个单词自动空格分隔,并且没有一个衡量标准好坏问题,词粒度分割不同,意思也就不同。

我们前面一直提到搜索和推荐场景,在这里,推荐适合粗粒度的分词,因为需要关心词的语义去推荐,而搜索适合细粒度的分词场景,侧重于召回更多的item到候选集合。

表示方法:

那我们如果对于一句话做分词,人类可以一眼就看出来,那么对于计算机来说怎么表示,那我们假设,切开位置表示为1,其他位置为0;那么这句话表示为:
有/意见/分歧——》11010
本田雅阁/汽车——》100010
那么这种表示方法对计算机确实很友好,但是对我们来说很头疼,于是通常情况下,我们用分词节点序列表示:
有/意见/分歧——》{0,1,3,5}

那么接下来的问题,这串索引怎么得到呢?
这里有一种原始方法:最大长度查找(字典匹配)
这个又分两种:前向查找,后向查找。
加载词典:

在查找过程中我们如果一个词一个词去匹配未免过于耗费资源,所以这里用一个加速查找字典的方法:trie树—数据结构

查找过程如下:
• 从根结点开始一次搜索;
• 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
• 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
• 迭代过程……
• 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。其他操作类似处理.
时间复杂度 O(n)—-空间换时间数据结构,并且在python中的字典数据结构这种速度是近乎于O(1)

匹配词典:

前面这是加载词典,而匹配词典是下面几种方法:
1、最大长度查找
前向查找:先从头匹配第一个字,之后看第二个字是否在第一个字后面,以此类推,若不在则砍一刀,之后继续查找当前第一个字。
后向查找:即语料库词为倒序,即反向建库
通常情况下后向查找会更符合语义。
2、
我们把每个字都分开,之后在语料库中匹配出每种排列组合的可能,用前面说的索引序列表示,与此同时,我们把每种可能都用一条线首尾相连,而这么多条线就构成了一张图:即有向无环图,也叫DAG图。

由此一句话的编码表示:DAG: {0: [0, 1, 3], 1: [1], 2: [2, 3, 5], 3: [3], 4: [4, 5], 5: [5], 6: [6, 7], 7: [7]}

那么我们这些边该如何去切分和选择呢?

由此引出:语言模型概念

我们由语料库已经有了很多列举后的切分方案,那么我们由这些切分方案可以得到每条方案的条件概率,比如:
C=本田雅阁汽车
S1=本田/雅阁/汽车
S2=本田雅阁/汽车
则:
P(S1|C)表示S1这条切分方案的条件概率

目标:我们希望得到的就是最大概率的那条切分方案。

那我们如何求取这条概率呢?:贝叶斯公式

p(s|c)=p(c|s)p(s)/p(c)

推导:
p(s|c) p(c)=p(s,c)—联合概率(同时发生的概率)
->p(c|s)p(s)=p(c,s)
-> p(s|c) p(c)= p(c|s)p(s)
-> p(s|c)= p(c|s)p(s)/p(c)

P(c):即这句话的概率,但是人类说每句话的概率都是相同的,即常量。
所以有:p(s|c)= p(c|s)p(s)
P(c|s):即p(本田雅阁汽车|本田/雅阁/汽车)=100%,即不管哪种切分方案都可以还原出原始的句子。
所以有:p(s|c)= p(s)
目标:P(S)
独立性假设,每个词之间无任何联系,都是独立的
那么有:p(本田/雅阁/汽车)=p(本田)p(雅阁)p(汽车)
也就是每个词token的概率:即TF——word count
由于P(S1)>p(S2),所以选P(S1)

那么由此我们选择概率最大的那条路线,就是这条句子的切分最佳方案。

但是,我们概率相乘是很容易形成很小的小数的,造成向下溢出,所以有:

求log后因为概率是小于1的数所以为负数,可比性高,并且加法运行速度比乘法更快。

我们前面是假设每个token前后是无关联关系的,但在实际生活中词与词都是有关联的,所以我们刚才的概率模型就是一元模型(只考虑到了词频概率)。

多元模型:
一元模型(Unigram) :一个词的出现不依赖于它前面出现的词—3个参数
P(S)=P(w1) P(w2)P(w3)…P(wn)
二元模型(Bigram):一个词的出现仅依赖于它前面出现的一个词—3+6个参数
P(S)=P(w1) P(w2|w1)P(w3|w2)…P(wn|wn-1)
三元模型 (Trigram):简化成一个词的出现仅依赖于它前面出现的两个词。3+6+。。

每次参数排列组合爆炸级增长。

J i e b a 分词简介
官方链接:https://github.com/fxsjy/jieba
jieba用于中文分词,支持的文本编码格式为utf-8,支持的功能包括:中文分词、关键字提取、词性标注
整体功能如下图:

框架结构:

第一阶段:加载词库,用trie树分割,生成句子中汉字所有可能成词情况所构成的DAG图—-FULL

词表格式: token,TF,词性 ——-》trie树——>DAG图——》找概率
Route概率:获得词频最大切分
P= TF / total(TF总和)—》log(p)—-》负数
总词数:
Linux:awk汉字计数:cat dict.txt | awk ‘BEGIN{a=0}{a+=$2}END{print a}’
—— 60101967(total)

第二阶段:动态规划或者贝叶斯计算最大路径概率,找出最大切分组合,Token英文中文识别
我们前面得到了每条边和每个汉字的概率(即所有可能词的概率),接着用倒序索引找最大路径(类似开始说的第二种表示方法)
route: {0: (-33.271126717488308, 1),
1: (-32.231489259807965, 1),
2: (-23.899234625632083, 5),
3: (-31.52324681384394, 3),
4: (-22.214895405024865, 5),
5: (-19.00846787368323, 5),
6: (-8.7800749471799175, 7),
7: (-8.800692190498415, 7), 8: (0.0, ‘’)}
从后向前导,每种切分方案是单个字概率大还是词概率大,确定后的方案概率不变,继续向前导,求最大方案,并累加概率值,以此类推。
所以最后方案:0-1,2-5,6-7
第三阶段:所有单个汉字的传给——>HMM模型粘贴词库中没有的被切碎的词(未登录词)—->再传回来改回为词更新句子,Viterbi动态规划算法
HMM:隐马尔科夫模型

实践:

  1. MR批量分词
    Client本地:代码、jieba包
    Datanode:数据
    文件分发—file模式—-代码内解压

2.pyweb+分词
Get、Post
引用jieba方法

上传的附件
最近文章
eject