自然语言处理入门->信息抽取、文本聚类、文本分类

1,222 阅读6分钟

此文为学习何晗老师《自然语言处理入门》笔记

信息抽取

  • 信息抽取:从非结构化文本中提取结构化信息的一类技术
    • 基于规则的正则匹配
    • 有监督机器学习
    • 无监督机器学习

信息熵(entropy)

  • 某条消息包含的信息量

H(X)=xp(x)logp(x)H(X) = - \sum_{x} p(x) \log p(x)

互信息(Mutual Information)

  • 指两个离散型随机变量XXYY的相关程度的度量。

I(X;Y)=x,ylogp(x,y)p(x)p(y)=Ep(x,y)logp(x,y)p(x)p(y)I(X; Y) = \sum_{x, y} \log \frac{p(x, y)}{p(x)p(y)} = E_{p(x, y)} \log \frac{p(x, y)}{p(x)p(y)}

具体到新词提取应用中:

  • XX:代表字符串的一个子串(前缀)
  • YY:代表母串去掉该前缀剩下的部分(后缀)

新词提取

有了左右信息熵和互信息之后,将两个指标低于一定阈值的片段过滤,剩下的片段按频次降序排列,截取最高频次的NN个片段即完成了词语提取流程。

关键词提取

词频统计

流程:

  • 分词
  • 停用词过滤
  • 按词频提取前nn

其中,求mm个元素中前nn大(nmn \le m)元素的问题通常通过最大堆解决,其复杂度为O(mlogn)O(m \log n)

TF-IDF

TF-IDF(Term Frequency-Inverse Document Frequency, 词频-倒排文档频次)

TFIDF(t,d)=TF(t,d)DF(t)=TF(t,d)IDF(t)TF-IDF(t, d) = \frac {TF(t,d)}{DF(t)} = TF(t,d) IDF(t)

其中

  • tt:单词(term)
  • dd:文档(document)
  • TF(t,d)TF(t,d):代表ttdd中出现频次
  • DF(t)DF(t):代表有多少篇文章包含tt
  • IDFIDFDFDF的倒数

TextRank

  • TextRank:PageRank在文本上的应用
  • PageRank:一种用于排序网页的随机算法。它的工作原理是将互联网看作是有向图,互联网上的网页视作节点,节点ViV_i到节点VjV_j的超链接视作有向边。初始化每个节点的权重S(Vi)S(V_i)都是1,以迭代的方式更新每个节点的权重:

?S(V_i) = (1 - d) + d \times \sum_{V_j \in In(V_i)} \frac {1} {|Out(V_j)|} S(V_j)?

  • dd:介于(0, 1)之间的常数因子,在PageRank中模拟用户点击链接从而跳出当前网站的概率
  • In(Vi)In(V_i):表示链接到ViV_i的节点集合
  • Out(Vj)Out(V_j):表示从VjV_j出发链接到的节点集合

有公式可以看出,外链接权重跟外链接总数成反比,与提供外链接的网站权重成正比。

PageRank应用到关键词提取:

  • 是将单词视作节点
  • 每个单词的外链接来自自身前后固定大小的窗口内的所有单词

for (int i = 0; i < max_iter; i++) {
    Map<String, Float> m = new HashMap<>();
    float max_diff = 0;
    // words存储着单词到邻居的映射
    for (Map.Entry<String, Set<String> entry : words.entrySet()) {
        String key = entry.getKey();
        Set<String> value = entry.getValue();
        m.put(key, 1 - d);
        // 对应上面求和公式
        for (String element : value) {
            int size = words.get(element).size();
            if (key.equals(element) || size == 0) continue;
            m.put(key, m.get(key) + d / size * (score.get(element) == null ? 0 : score.get(element)));
        }
        max_diff = Math.max(max_diff, Math.abs(m.get(key) - (score.get(key) == null ? 0 : score.get(key))));
    }
    score = m;
    if (max_diff <= min_diff) break;
}

短语提取

短语提取经常用于搜索引擎的自动推荐,文档的简介生成等。

利用互信息和左右信息熵,只需将新词提取时的字符替换为单词,字符串替换为单词列表即可。

关键句提取

为了将PageRank利用到句子颗粒度上去,引入了BM25算法衡量句子的相似度,改进链接的权重。这样的窗口的中心句子与相邻的句子间的链接变的有强有弱,相似的句子将得到更高的投票。

BM25

在信息检索领域,BM25是TF-IDF的一种改进变种。

  • TF-IDF:衡量单个词语在文档中的重要程度
  • BM25:衡量多个词语与文档的关联程度

BM25(D,Q)=i=1nIDF(qi)TF(qi,D)(k+1TF(qi,D)+k(1b+bDavgDL)BM25(D, Q) = \sum_{i=1}^n IDF(q_i) \cdot \frac{TF(q_i, D) \cdot (k + 1)}{TF(q_i, D) + k \cdot (1 - b + b \cdot \frac {|D|}{avg DL})}

  • QQ:查询语句
  • q1,,qnq_1, \cdots, q_nQQ中关键字
  • DD:为一个被检索的文档
  • k,bk, b:常数,与TFTF可视做IDFIDF的权重参数,kk越大,TFTF对文档得分的正面影响越大,bb越大,文档长度对得分的负面影响越大。当k=b=0k = b = 0时,BM25BM25完全等价于所有单词的IDFIDF之和。
  • avgDLavg DL:所有文档平均长度
/**
 * 计算一个句子与一个文档的BM25相似度
 * @param sentence 句子(查询语句)
 * @param index 文档(用语料库中的下标表示)
 */
double sim(List<String> sentence, int index) {
    double score = 0;
    for (String word : sentence) {
        if (! f[index].containsKey(word)) {
            continue;
        }
        int d = docs.get(index).get(word);
        int tf = f[index].get(word);
        score += (idf.get(word) * tf * (k + 1) / (tf + k * (1 - b + b * d / avgdl)));
    }
    return score;
}

TextRank

将一个句子视作查询语句,相邻的句子视作待查询的文档,就能得到他们之间的相似度。以此相似度作为PageRank中的链接的权重,于是得到一种改进算法TextRank:

WS(Vi)=(1d)+d×VjIn(Vi)BM25(Vi,Vj)VkOut(Vj)BM25(Vk,Vj)WS(Vj)WS(V_i) = (1-d) + d \times \sum_{V_j \in In(V_i)} \frac {BM25(V_i, V_j)} {\sum_{V_k \in Out(V_j)} BM25(V_k, V_j)} WS(V_j)

  • WS(Vi)WS(V_i):文档中第ii个句子的得分,重复迭代若干次即可得到最终分值
for (int iter = 0; iter < max_iter; ++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 == i || 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_dff <= min_diff) {
        break;
    }
}

总结

新词提取与短语提取,关键词与关键句的提取,在原理上都是同一种算法在不同文本颗粒度上的应用。这些算法都无需标注语料参与,属于无监督学习。

文本聚类

聚类(cluster analysis)指的是将给定对象的集合划分为不同子集的过程。

  • 硬聚类(hard clustering):每个元素被确定地归入一个簇
  • 软聚类(soft clustering):每个元素与每个簇都存在一定的从属程度(隶属度),只不过该程度有大有小

根据聚类结果的结构,分为:

  • 划分式(partitional):一些列不想交的子集

  • 层次化(hierarchial):一棵树,叶子节点是元素,父节点是簇

  • 文本聚类(text clustering):指的是对文档进行的聚类分析。广泛应用于文本挖掘和信息检索领域。

文本聚类基本流程:

  1. 特征提取
  2. 向量聚类

文档的特征提取

词袋模型

  • 词袋(bag-of-words):信息检索与自然语言处理中最常用的文档表示模型,它将文档想象为一个装有词语的袋子,通过袋子中每种词语的计数等统计量将文档表示为向量。

定义由nn个文档组成的集合SS,定义其中第ii个文档did_i的特征向量:

di=(TF(t1,di),,TF(tj,di),,TF(tm,di))d_i = (TF(t_1, d_i), \cdots, TF(t_j, d_i), \cdots, TF(t_m, d_i))

  • tjt_j:词表中第jj种单词,mm为词表大小
  • TF(tj,di)TF(t_j, d_i):表示单词tjt_j在稳定did_i中出现次数。 做归一化处理d=1||d|| = 1

从文本到向量的转换已经执行完毕。

kk均值算法

给定nn个向量d1,,dnRld_1, \cdots, d_n \in R^l,以及一个整数kk,要求找出kk个簇S1,,SkS_1, \cdots, S_k,以及各自的质心c1,,ckRlc_1, \cdots, c_k \in R^l,使得下式值最小: minimizeΓEuclidean=r=1kdiSrdicr2minimize \Gamma_{Euclidean} = \sum_{r = 1}^{k} \sum_{d_i \in S_r}||d_i - c_r||^2

  • dicr2||d_i - c_r||^2:向量与质心的欧拉距离
  • ΓEuclidean\Gamma_{Euclidean}:聚类的准则函数(criterion function).

质心的计算就是簇内数据点的几何平均:

  • si=djSidjs_i = \sum_{d_j \in S_i} d_j

  • ci=siSic_i = \frac {s_i} {S_i}

其中,sis_i是簇SiS_i内所有向量之和,成作合成向量(compose vector)。

生成kk个簇的kk均值迭代算法:

  1. 选取kk个点作为kk个簇的初始质心
  2. 将所有点分布分配给最近的质心所在的簇
  3. 重新计算每个簇的质心
  4. 重复2到3,直至之心不在发生变化

kk均值算法无法保证收敛到全局最优,但能够保证有效地收敛到一个局部最优点。

初始质心的选取

将之心的选取也视作准则函数进行迭代优化:

  1. 随机选取一个数据点作为质心,视作只有一个簇计算准则函数。同时维护每个点到最近质心的距离的平方,作为一个映射数组MM
  2. 随机取准则函数值的一部分Δ\Delta
  3. 遍历剩下的所有数据点,若改点到质心的距离的平方小于Δ\Delta,则选取该点添加到质心列表,同时更新准则函数与MM
  4. 循环2到3,直至凑足kk个初始质心
/**
 * 选取初始质心
 * @param ndocs 质心数量
 * @param docs 输出到该列表中
 */
void choose_smartly(int ndocs, List<Document> docs) {
    double po
}

文本分类

  • 文本分类(text classification):又称文档分类,是将一个归类到一个或多个类别中的自然语言处理任务。是一个典型的监督学习任务,其流程离不开人工指导:人工标注文档类别。

应用:

  • 垃圾邮件过滤
  • 垃圾评论过滤
  • 自动标签
  • 情感分析

依存句法分析

短语结构树

上下文无关法(Context-Free Grammer, CFG)

  • 终结符(teminal symbol,无法再分的最小单位)集合Σ\Sigma,比如汉语的一个词表
  • 非终结符(nontermial symbol)集合VV,比如“名词短语”“动词短语”等短语结构组成的集合。VV 中至少包含一个特殊的非终结符,即句子符或初始符,记作SVS \in V
  • 推导规则RR,即推导非终结符的一系列规则:VVΣV \rightarrow V \cup \Sigma

语法树其实与编译原理相应概念相同,但在NLP中,我们称其为短语结构树。

短语结构树

短语结构语法描述了如何自顶而下地生成一个句子。反过来,句子也可以用短语结构语法来递归地分解。

树库(treebank):语言学家制定短语结构语法规范,将大量句子人工分解为树形结构,形成一种语料库

依存句法树

不同于短语结构树,依存句法树并不关注如何生成句子这种宏大的命题。依存句法树关注的是句子中词语之间的语法联系,并将其约束为树形结构。

依存语法理论:词与词之间存在主从关系,这是一种二元不等价的关系。

  • 从属词(dependent):如果一个词修饰领一个词
  • 支配词(head):被修饰的词语
  • 依存关系(dependency relation):两者之间的语法关系

依存语法树4个约束性公理

  • 有且只有一个词语(ROOT,虚拟根节点,简称虚根)不依存于其他词语
  • 除此之外所有单词必须依存于其他单词
  • 每个单词不能依存于多个单词
  • 如果单词AA依存于BB,那么位置处于AABB之间的单词CC只能依存于AABBABAB之间的单词

依存句法分析

依存句法分析(dependency parsing)指的是分析句子的依存语法的一种高级NLP任务,其输入通常是词语和词性,输出则是一颗依存句法树。

  • 基于图的依存句法分析:依存语法树其实是完全图(complete graph,每个顶点都相连的图)的一个子图。
  • 基于转移的依存句法分析

深度学习与自然语言处理

传统方法的局限

数据稀疏

  • 传统机器学习方法不善于处理数据稀疏问题
  • 语言是离散的符号系统,每个字符,每个单词都是离散型随机变量
  • 任何机器学习模型只接受向量
  • One-Hot模型会导致稀疏矩阵问题

词向量:将离散单词表示为稠密向量

特征模板

传统自然语言处理依赖于手工指定的特征模板,这些特征模板通常是小颗粒度文本单元的组合,用以模拟语言的符合过程

误差传播

深度学习与优势

  • 用稠密向量解决数据稀疏
  • 用多层网络自动提取特征表示
  • 端到端的设计

Word2Vec

CBOW(Continuous Bag of Words Model)是一种基于窗口的语言模型。一个窗口指的是句子中的一个固定长度的片段,窗口中间的词语称为中心词。窗口中其他词语称为中心词的上下文。CBOW模型通过三层神经网络接受上下文的特征向量,预测中心词是什么。