信息抽取
信息抽取是个宽泛的概念,指的是从非结构化的文本中提取出结构化的信息来的一种技术。信息抽取(information extraction),即从自然语言文本中,抽取出特定的事件或事实信息,帮助我们将海量内容自动分类、提取和重构。信息通常包括实体(entity)、关系(relation)、事件(event)
新词提取
新词
新词指的是词典之外的词语。新词的提取分为:
- 提取大量的文本(生语料)中的词语,无论新旧
- 用词典过滤掉已有的词语,得到新的词语
信息熵
信息熵指的是某条消息所含的信息量。不确定性越大,信息量越大。计算方法如下:
如果对数函数的底数是2,信息上的单位就是比特
具体到新词提取中,给定字符串S作为词语选取,X定义为左边可能出现的字符(左邻字),则成H(X)为S的左信息熵。
互信息
互信息指的是两个离散型随机变量XY之间的相关程度的度量。 $$ begin{align} I(X;Y) & =sum_{x,y}p(x,y)log frac{p(x,y)}{p(x)p(y)} & = E_{p(x,y)} logfrac{p(x,y)}{p(x)p(y)} end{align} $$ 在韦恩图中,
- 并集:联合分布的信息熵H(X,Y)
- 差集:条件熵H(X|Y)
- 交集:互信息H(X;Y)
互信息越大,两个变量的关系越密切。同时发生的可能性也就越大。
提取新词
有了信息熵和互信息,将两个指标低于一定阈值的片段过滤掉,剩下的片段按照频次降序排列,截取最高频次的N个片段,完成词语的提取流程。具体模块在com.hankcs.hanlp.mining.word.NewWordDiscover
,相应的接口为com.hankcs.hanlp.HanLP#extractWords
word_life_list = HanLP.extractWords(IOUtil.newBufferedReader(corpus), 100) # 提取100个关键词
接口的参数为
- reader 从reader中获取文本,逐行读取和处理,内存更省
- size 需要提取词语的数量
- NewWordsOnly 是否只提取词典中没有的词语,返回
OOV
- max_word_len 词语最长长度,默认是4
- min_freq 词语最低频率
- min_entropy 词语最低熵。0.5左右,该值越大,越短的词语越容易被提取出来。
- min_aggregation 词语最低互信息,一般50-200。该值越大,越长的词语越容易被提取出来
关键词提取
提取文章中重要的单词,而不是限于词语的新鲜程度,成为关键词提取
在进行提取的过程中,根据一份还是多份文档,提取算法分为单文档和多文档算法。
- 单文档:词频和TextRank
- 多文档:TF-IDF
词频
文章中作者反复提及到的词语,通过统计文章每种词语的词频并排序,获取关键词。但是比如某些词语,比如“的”反复出现,但是并不是关键词。词频统计的步骤:
- 分词
- 停用词过滤
- 按词频统计前n个
counter = TermFrequencyCounter()
counter.add("加油加油中国队")
counter.add("中国观众在给中国队加油")
for termFrequency in counter:
print("%s = %d" %(termFrenquency.getTrem(), termFrequency.getFrequency()))
print(counter.top(2))
# 结果
中国=2
中国队=1
加油=3
观众=1
高呼=1
[加油=3,中国=1]
[女排,观众,欢呼]
- 遍历counter默认是按照字典顺序遍历
- top(N)返回的是词频最高的前N个单词及词频,降序排列
- 标点符号等停用分词已经去除了,分词结果以语境为主
- 索引模式:激活内置分词器的索引模式
counter.getSegment().enableIndexMode(true); # 激活索引模式
counter.setSegment(new PerceptronLexicalAnalyzer().enableIndexMode(true)); # 切换分词器
笔记:使用词频统计的缺陷是,高频词语不等价于关键词。比如所有报道“奥运会”的文章中,将“奥运会”作为关键词并不合适,用户希望看到的是每篇文章的特色之处,而不是共性。
TF-IDF
TF-IDF(Term Frequency-Inverse Document Frequency, 词频-倒排文档频次)是信息检索中一个重要的词语重要程度的统计指标,广泛用于搜索引擎中,它属于多文档提取方法。综合考虑词语的稀有程度:
- 正比于它在文中的频次
- 反比于有多少文档包含它:包含该词语的文档越多,越不能体现文档的特色。
- 计算方法有多种,如下一种
上面每个参数的解释
t
代表的是term
d
代表的是document
TF(t,d)
代表的是t
在d
中的出现频次DF(t)
代表的是多少篇文档包含t
- DF的倒数成为IDF
counter = TfIdfCounter() # 调用方法的类
counter.add("<id1>, <内容>") # 输入多篇文章
counter.add("<id2>, <内容>")
counter.add("<id3>, <内容>")
counter.compute() # 输入完毕
for id in counter.documents():
print(id ":" counter.getKeywordsOf(id, 3).toString()) # 根据每篇文章的TF-IDF提取关键词
add
函数接受两个参数:文档id
和文档内容documents
方法返回所有的文档id
,供用户遍历getKeywordsOf(id, 3)
的两个参数:文档id
和提取的关键词个数
TextRank
如果没有大型的语料库或者存储IDF的内存,又想改善瓷片统计的效果,使用TextRank方法。TextRank实际上就是谷歌的PageTank文本上的应用
PageRank
是一种用于排序网页的随机算法。基本原理如下
- 互联网看作是有向图,网页视作为节点
- 节点V_i到节点V_j的超链接视作有向边
- 初始化每个节点的权重S(V_i)都是1,通过迭代的方式更新每个节点的权重,更新的表达式为
- d是0-1之前的常数因子,用户点击链接跳出当前链接当前网站的概率
- In(V_i)表示链接V_i的集合
- Out(V_j)表示从v_j出发链接到的集合
- 外链权重和外链总数成反比,与提供外链的网站权重成正比
笔记:并不是外链越多,PR就越高。外链越多,权重就越低。
PageRank应用到关键词提取中,将单词看做是节点。每个单词的外链是来自前后固定大小的窗口内的所有单词。
代码语言:javascript复制keyword_list = HanLP.extractKeyWord(content, 5)
短语提取
固定多词表达串的识别。常用于搜索引擎的自动推荐,文档的简介生成等。
代码语言:javascript复制pharse_list = HanLP.extractPharse(text, 5) # 两个参数是文档的内容和所需短语个数
关键句提取
BM25
一般的PageRank
在句子颗粒度上行不通的,因为一篇文章中几乎不会出现两句完全相同的句子。引入了BM25
算法衡量句子的相似度,改进连接的权重计算。
在搜索引擎中,查询串query
是由多个词语构成的。BM25
解决的是衡量多个词语与文档的关联程度。几个定义如下:
- Q为查询语句,由关键字q_1,…,q_n组成
- D是被检索的文档
- k_l和d是两个常量,avgDL是所有文档的平均长度
BM25的定义如下:
上面式子的特点
- 先对查询语句中所有单词的
IDF
加权求和,两个参数和TF可以看做是调整IDF权重的参数 - k_1越大,TF对正面文档得分的正面影响就越大;b越大,TF负面文档得分的正面影响就越大
- 在
TF-IDF
中,当IDF
固定时,得分正比于TF,长文档占据优势;BM25
中,TF
对得分的影响还必须考虑文档长度
TF-IDF的表达式再现:
TextRank
在上面的BM25算法中,将句子视作一个查询语句,相邻的句子视作待查询的文档,得到它们之间的相似度。将该相似度看做是PageRank中链接的权重,得到了TextRank算法。
TextRank关键句提取模块的实现为TextRankSentence。核心的Java代码为
代码语言:javascript复制for (int _ = 0; _ < max_iter; _)
{
double[] m = new double[D];
double max_diff = 0;
for (int i = 0; i < D; i)
{
m[i] = 1 - d;
for (int j = 0; j < D; j) /*上面表达式中的第一个求和式子*/
{
if (j == 1 || weight_sum[j] == 0) continue;
m[i] = (d * weight[j][i] / weight_sum[j] * vertex[j]);
}
double diff = Math.abs(m[i] - vertex[i]);
if (diff > max_diff)
{
max_diff = diff;
}
}
vertex = m;
if (max_diff <= min_diff) break;
}
当两次迭代间权重最大变化量小于阈值min_diff
,或者总的迭代次数达到max_iter
时算法终止。
sentence_list = HanLP.extractSummary(document,3) # 两个参数:文档和所需要的句子数量