【分词】文本挖掘的分词原理

前言

在做文本挖掘的时候,首先要做的预处理就是分词。英文单词天然有空格隔开容易按照空格分词,但是也有时候需要把多个单词做为一个分词,比如一些名词如“New York”,需要做为一个词看待。而中文由于没有空格,分词就是一个需要专门去解决的问题了。无论是英文还是中文,分词的原理都是类似的,本文就对文本挖掘时的分词原理做一个总结。

1. 分词的基本原理

现代分词都是基于统计的分词,而统计的样本内容来自于一些标准的语料库。假如有一个句子:“小明来到荔湾区”,我们期望语料库统计后分词的结果是:“小明/来到/荔湾/区”,而不是“小明/来到/荔/湾区”。那么如何做到这一点呢?

从统计的角度,我们期望"小明/来到/荔湾/区"这个分词后句子出现的概率要比“小明/来到/荔/湾区”大。如果用数学的语言来说说,如果有一个句子 S S S, 它有m种分词选项如下
A 11 A 12 ⋯ A 1 n 1 A 21 A 22 ⋯ A 2 n 2 ⋯ ⋯ ⋯ A m 1 A m 2 . . . A m n m A_{11}A_{12} \cdots A_{1n1}\\ A_{21}A_{22} \cdots A_{2n2}\\ \cdots \cdots \cdots \\ A_{m1}A_{m2}...A_{mn_m}\\ A11A12A1n1A21A22A2n2Am1Am2...Amnm
其中下标 n i n_i ni代表第 i i i种分词的词个数。如果我们从中选择了最优的第 r r r种分词方法,那么这种分词方法对应的统计分布概率应该最大,即:

r = a r g   m a x ⏟ i P ( A i 1 , A i 2 , ⋯   , A i n i ) r = \begin{matrix} \underbrace{arg \ max } \\ i \end{matrix}P(A_{i1},A_{i2},\cdots,A_{ini}) r= arg maxiP(Ai1,Ai2,,Aini)
但是我们的概率分布 P ( A i 1 , A i 2 , ⋯   , A i n i ) P(A_{i1},A_{i2}, \cdots ,A_{ini}) P(Ai1,Ai2,,Aini)并不好求出来,因为它涉及到 n i n_i ni个分词的联合分布。在NLP中,为了简化计算,我们通常使用马尔科夫假设,即每一个分词出现的概率仅仅和前一个分词有关,即:
P ( A i j ∣ A i 1 , A i 2 , ⋯   , A i ( j − 1 ) ) = P ( A i j ∣ A i ( j − 1 ) ) P(A_{ij}|A_{i1},A_{i2}, \cdots ,A_{i(j−1)})=P(A_{ij}|A_{i(j−1)}) P(AijAi1,Ai2,,Ai(j1))=P(AijAi(j1))

在前面我们讲MCMC采样时,也用到了相同的假设来简化模型复杂度。使用了马尔科夫假设,则我们的联合分布就好求了,即:
P ( A i 1 , A i 2 , ⋯   , A i n i ) = P ( A i 1 ) P ( A i 2 ∣ A i 1 ) P ( A i 3 ∣ A i 2 ) ⋯ P ( A i n i ∣ A i ( n i − 1 ) ) P(A_{i1},A_{i2},\cdots,A_{in_i})=P(A_{i1})P(A_{i2}|A_{i1})P(A_{i3}|A_{i2}) \cdots P(A_{in_i}|A_{i(n_{i−1})}) P(Ai1,Ai2,,Aini)=P(Ai1)P(Ai2Ai1)P(Ai3Ai2)P(AiniAi(ni1))
而通过我们的标准语料库,我们可以近似的计算出所有的分词之间的二元条件概率,比如任意两个词w1,w2,它们的条件概率分布可以近似的表示为:
P ( w 2 ∣ w 1 ) = P ( w 1 , w 2 ) P ( w 1 ) ≈ f r e q ( w 1 , w 2 ) f r e q ( w 1 )     P ( w 1 ∣ w 2 ) = P ( w 2 , w 1 ) P ( w 2 ) ≈ f r e q ( w 1 , w 2 ) f r e q ( w 2 ) P(w2|w1)=\frac{P(w1,w2)}{P(w1)}≈\frac{freq(w1,w2)}{freq(w1)} ~\\ ~\\ P(w1|w2)=\frac{P(w2,w1)}{P(w2)}≈\frac{freq(w1,w2)}{freq(w2)} P(w2w1)=P(w1)P(w1,w2)freq(w1)freq(w1,w2)  P(w1w2)=P(w2)P(w2,w1)freq(w2)freq(w1,w2)

其中 f r e q ( w 1 , w 2 ) freq(w1,w2) freq(w1,w2)表示 w 1 w1 w1, w 2 w2 w2在语料库中相邻一起出现的次数,而其中 f r e q ( w 1 ) , f r e q ( w 2 ) freq(w1),freq(w2) freq(w1),freq(w2)分别表示 w 1 , w 2 w1,w2 w1,w2在语料库中出现的统计次数。

利用语料库建立的统计概率,对于一个新的句子,我们就可以通过计算各种分词方法对应的联合分布概率,找到最大概率对应的分词方法,即为最优分词

2. N元模型

当然,你会说,只依赖于前一个词太武断了,我们能不能依赖于前两个词呢?即:
P ( A i 1 , A i 2 , ⋯   , A i n i ) = P ( A i 1 ) P ( A i 2 ∣ A i 1 ) P ( A i 3 ∣ A i 1 , A i 2 ) . . . P ( A i n i ∣ A i ( n i − 2 ) , A i ( n i − 1 ) ) P(A_{i1},A_{i2},\cdots,Aini)=P(Ai1)P(Ai2|Ai1)P(Ai3|Ai1,Ai2)...P(Aini|Ai(ni−2),Ai(ni−1)) P(Ai1,Ai2,,Aini)=P(Ai1)P(Ai2Ai1)P(Ai3Ai1Ai2)...P(AiniAi(ni2)Ai(ni1))

这样也是可以的,只不过这样联合分布的计算量就大大增加了。我们一般称只依赖于前一个词的模型为二元模型(Bi-Gram model),而依赖于前两个词的模型为三元模型。以此类推,我们可以建立四元模型,五元模型,…一直到通用的 N N N元模型。越往后,概率分布的计算复杂度越高。当然算法的原理是类似的。

在实际应用中, N N N一般都较小,一般都小于4,主要原因是 N N N元模型概率分布的空间复杂度为 O ( ∣ V ∣ N ) O(|V|^N) O(VN),其中 ∣ V ∣ |V| V为语料库大小,而 N N N为模型的元数,当N增大时,复杂度呈指数级的增长。

N元模型的分词方法虽然很好,但是要在实际中应用也有很多问题,首先,某些生僻词,或者相邻分词联合分布在语料库中没有,概率为0。这种情况我们一般会使用拉普拉斯平滑,即给它一个较小的概率值,这个方法在朴素贝叶斯算法原理小结也有讲到。第二个问题是如果句子长,分词有很多情况,计算量也非常大,这时我们可以用下一节维特比算法来优化算法时间复杂度。

3. 维特比算法与分词

为了简化原理描述,我们本节的讨论都是以二元模型为基础。

对于一个有很多分词可能的长句子,我们当然可以用暴力方法去计算出所有的分词可能的概率,再找出最优分词方法。但是用维特比算法可以大大简化求出最优分词的时间。

大家一般知道维特比算法是用于隐式马尔科夫模型HMM解码算法的,但是它是一个通用的求序列最短路径的方法,不光可以用于HMM,也可以用于其他的序列最短路径算法,比如最优分词。

维特比算法采用的是动态规划来解决这个最优分词问题的,动态规划要求局部路径也是最优路径的一部分,很显然我们的问题是成立的。首先我们看一个简单的分词例子:“人生如梦境”。它的可能分词可以用下面的概率图表示:


图中的箭头为通过统计语料库而得到的对应的各分词位置BEMS(开始位置,结束位置,中间位置,单词)的条件概率。比如 P ( 生 ∣ 人 ) = 0.17 P(生|人)=0.17 P()=0.17。有了这个图,维特比算法需要找到从Start到End之间的一条最短路径。对于在End之前的任意一个当前局部节点,我们需要得到到达该节点的最大概率 δ δ δ,和记录到达当前节点满足最大概率的前一节点位置 Ψ Ψ Ψ

我们先用这个例子来观察维特比算法的过程。首先我们初始化有:
δ ( 人 ) = 0.26 Ψ ( 人 ) = S t a r t δ ( 人 生 ) = 0.44 Ψ ( 人 生 ) = S t a r t δ(人)=0.26Ψ(人)=Startδ(人生)=0.44Ψ(人生)=Start δ()=0.26Ψ()=Startδ()=0.44Ψ()=Start
对于节点"生",它只有一个前向节点,因此有:
δ ( 生 ) = δ ( 人 ) P ( 生 ∣ 人 ) = 0.0442 Ψ ( 生 ) = 人 δ(生)=δ(人)P(生|人)=0.0442Ψ(生)=人 δ()=δ()P()=0.0442Ψ()=
对于节点"如",就稍微复杂一点了,因为它有多个前向节点,我们要计算出到“如”概率最大的路径:

δ ( 如 ) = m a x { δ ( 生 ) P ( 如 ∣ 生 ) , δ ( 人 生 ) P ( 如 ∣ 人 生 ) } = m a x { 0.01680 , 0.3168 } = 0.3168   Ψ ( 如 ) = 人 生 δ(如)=max\{δ(生)P(如|生),δ(人生)P(如|人生)\}=max\{0.01680,0.3168\}=0.3168 \ Ψ(如)=人生 δ()=max{δ()P()δ()P()}=max{0.01680,0.3168}=0.3168 Ψ()=
类似的方法可以用于其他节点如下:
δ ( 如 梦 ) = δ ( 人 生 ) P ( 如 梦 ∣ 人 生 ) = 0.242 Ψ ( 如 梦 ) = 人 生 δ ( 梦 ) = δ ( 如 ) P ( 梦 ∣ 如 ) = 0.1996 Ψ ( 梦 ) = 如 δ ( 境 ) = m a x { δ ( 梦 ) P ( 境 ∣ 梦 ) , δ ( 如 梦 ) P ( 境 ∣ 如 梦 ) } = m a x { 0.0359 , 0.0315 } = 0.0359 Ψ ( 境 ) = 梦 δ ( 梦 境 ) = δ ( 如 ) P ( 梦 境 ∣ 如 ) = 0.1616 Ψ ( 梦 境 ) = 如 δ(如梦)=δ(人生)P(如梦|人生)=0.242Ψ(如梦)=人生 \\ δ(梦)=δ(如)P(梦|如)=0.1996Ψ(梦)=如\\ δ(境)=max\{δ(梦)P(境|梦),δ(如梦)P(境|如梦)\}=max\{0.0359,0.0315\}=0.0359Ψ(境)=梦\\ δ(梦境)=δ(如)P(梦境|如)=0.1616Ψ(梦境)=如 δ()=δ()P()=0.242Ψ()=δ()=δ()P()=0.1996Ψ()=δ()=max{δ()P(),δ()P()}=max{0.0359,0.0315}=0.0359Ψ()=δ()=δ()P()=0.1616Ψ()=
最后我们看看最终节点End:
δ ( E n d ) = m a x { δ ( 梦 境 ) P ( E n d ∣ 梦 境 ) , δ ( 境 ) P ( E n d ∣ 境 ) } = m a x { 0.0396 , 0.0047 } = 0.0396   Ψ ( E n d ) = 梦 境 δ(End)=max\{δ(梦境)P(End|梦境),δ(境)P(End|境)\}=max\{0.0396,0.0047\}=0.0396\ Ψ(End)=梦境 δ(End)=max{δ()P(End),δ()P(End)}=max{0.0396,0.0047}=0.0396 Ψ(End)=
由于最后的最优解为“梦境”,现在我们开始用 Ψ Ψ Ψ反推:
Ψ ( E n d ) = 梦 境 → Ψ ( 梦 境 ) = 如 → Ψ ( 如 ) = 人 生 → Ψ ( 人 生 ) = s t a r t Ψ(End)=梦境→Ψ(梦境) = 如→Ψ(如) = 人生→Ψ(人生) = start Ψ(End)=Ψ()=Ψ()=Ψ()=start
从而最终的分词结果为"人生/如/梦境"。是不是很简单呢。

由于维特比算法我会在后面讲隐式马尔科夫模型HMM解码算法时详细解释,这里就不归纳了。

4. 常用分词工具

对于文本挖掘中需要的分词功能,一般我们会用现有的工具。简单的英文分词不需要任何工具,通过空格和标点符号就可以分词了,而进一步的英文分词推荐使用nltk。对于中文分词,则推荐用结巴分词(jieba)。这些工具使用都很简单。你的分词没有特别的需求直接使用这些分词工具就可以了。

5. 结语

分词是文本挖掘的预处理的重要的一步,分词完成后,我们可以继续做一些其他的特征工程,比如向量化(vectorize),TF-IDF以及Hash trick,这些我们后面再讲。

文本挖掘是指从大量文本数据中自动提取出有用的信息和知识的过程。而jieba分词是一种常用的中文分词工具,可以将中文文本按照词语切分成若干个词汇,从而为文本挖掘提供了基础。 以下是用jieba分词进行文本挖掘的步骤: 1. 导入jieba库 ``` import jieba ``` 2. 加载文本数据 假设我们有一个文本文件,名为“data.txt”,其中包含一些中文文本数据。我们可以使用以下代码将文本数据读入程序中: ``` with open('data.txt', 'r', encoding='utf-8') as f: text = f.read() ``` 3. 对文本数据进行分词 使用jieba分词对文本数据进行分词,得到词语列表: ``` words = jieba.lcut(text) ``` 4. 进行文本挖掘 利用分词得到的词语列表进行文本挖掘。常见的文本挖掘任务包括: - 关键词提取:从文本中提取出关键词,用于文本分类、聚类等任务。 ``` import jieba.analyse # 提取前10个关键词及其权重 keywords = jieba.analyse.extract_tags(text, topK=10, withWeight=True) for keyword, weight in keywords: print(keyword, weight) ``` - 情感分析:判断文本的情感倾向,如积极、消极或中性。 ``` import jieba.sentiment # 加载情感分析模型 jieba.sentiment.analyse.set_sentiment_file('sentiment.txt') # 获取文本的情感倾向 sentiment_score = jieba.sentiment.analyse.sentiment(text) if sentiment_score > 0: print('这是一篇积极的文章') elif sentiment_score < 0: print('这是一篇消极的文章') else: print('这是一篇中性的文章') ``` - 主题建模:从文本中提取出主题,用于文本分类、聚类等任务。 ``` import jieba.analyse from gensim import corpora, models # 提取关键词列表 keywords = jieba.analyse.extract_tags(text, topK=10) # 构建语料库 corpus = [jieba.lcut(sentence) for sentence in text.split('\n')] # 构建词袋模型 dictionary = corpora.Dictionary(corpus) corpus_bow = [dictionary.doc2bow(sentence) for sentence in corpus] # 训练LDA模型 lda_model = models.ldamodel.LdaModel(corpus_bow, num_topics=3, id2word=dictionary) # 输出每个主题的关键词 for i, topic in enumerate(lda_model.show_topics(num_topics=3, num_words=5)): print('主题%d:%s' % (i+1, topic)) ``` 以上是用jieba分词进行文本挖掘的基本步骤和常见任务。需要注意的是,jieba分词只是文本挖掘的一部分,实际的文本挖掘任务涉及到多个领域的知识,需要综合运用自然语言处理、机器学习、统计学等方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值