什么是LDA?

潜在狄利克雷分配(LDA),作为基于贝叶斯学习的话题模型,是潜在语义分析、概率潜在语义分析的扩展,于2002年由Blei等提出。LDA在文本数据挖掘、图像处理、生物信息处理等领域被广泛使用。

LDA模型是文本集合的生成概率模型。假设每个文本由话题的一个多项式分布表示,每个话题由单词的一个多项式分布表示,特别假设文本的话题分布的先验分布是狄利克雷分布,话题的单词分布的先验分布也是狄利克雷分布。先验分布的导入使LDA能够更好地应对话题模型学习的过拟合现象。

LDA的文本集合的生成过程如下:首先随机生成一个文本话题分布,之后再该文本的每个位置,依据该文本的话题分布随机生成一个话题,然后在该位置依据该话题的单词分布随机生成一个单词,直至文本的最后一个位置,生成整个文本。重复以上的过程生成所有文本。

LDA模型是含隐变量的概率图模型。模型中,每个话题的单词分布,每个文本的话题分布,文本的每个位置的话题是隐变量;文本的每个文职的单词是观测变量。LDA模型的学习与推理无法直接求解,通常使用吉布斯抽样和变分EM算法。前者是蒙特卡洛法,后者是近似计算。

LDA是常见的主题模型之一,是一类无监督学习算法,在训练时不需要手工标注的训练集,需要的仅仅是文档集以及指定主题的数量k即可。此外LDA的另一个优点则是,对于每一个主题均可找出一些词语来描述它。

狄利克雷分布

1.分布定义

多项分布是一种多元离散随机变量的概率分布,是二项分布的扩展。

假设重复进行n次独立随机试验,每次试验可能出现的结果有k种,第i中结果出现的概率为

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配

,第i种结果出现的次数为

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_02

。如果用随机变量

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_03

,表示试验所有可能结果的次数,其中

Python 中的潜在狄利克雷分配 (LDA) 算法_LDA_04

表示第i种结果出现的次数,那么随机变量

Python 中的潜在狄利克雷分配 (LDA) 算法_LDA_05

服从多项分布。若元离散随机变量的概率密度为

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_06


其中

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_07

,,则称随机变量X服从参数为(n,p)的多项分布,记作

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_08

当试验的次数n为1时,多项分布变成类别分布。类别分布表示试验可能出现的k种结果的概率。显然多先分布包含类别分布。

2.狄利克雷分布

狄利克雷分布是一种多元随机变量的概率分布,是贝塔分布的扩展。在贝爷斯学习中,狄利克雷分布作为多项分布的先验概率使用。

多元连续型随机变量

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_09

的概率密度函数为

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_10


其中

\sum_{i=1}^k \Theta_i = 1,\Theta_i \ge 0,\alpha=(\alpha_1,\alpha_2,\dots,\alpha_k) ,\alpha_i > 0,i=1,2,\dots,k

,称随机变量

Python 中的潜在狄利克雷分配 (LDA) 算法_LDA_12

服从参数为

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_13

的狄利克雷分布,记作

Python 中的潜在狄利克雷分配 (LDA) 算法_LDA_14


式中

\Gamma(s) = \int_{0}^{\infty} x^{s-1}e^{-x} ds,s > 0

具有以下性质

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_16


当s是自然数时,有

Python 中的潜在狄利克雷分配 (LDA) 算法_LDA_17


Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_18


则狄利克雷分布的密度函数可以写成

Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_19

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_20

是规范化因子,称为多元贝塔函数(称为扩展的贝塔函数)。由密度函数性质

Python 中的潜在狄利克雷分配 (LDA) 算法_狄利克雷分配_21


Python 中的潜在狄利克雷分配 (LDA) 算法_贝叶斯模型_22

LDA如何运作?

在 LDA 中执行以下步骤,为每个文档分配主题:

1) 对于每个文档,将每个单词随机初始化为 K 个主题中的一个主题,其中 K 是预定义主题的数量。

2) 对于每个文档 d:

对于文档中的每个单词 w,计算:

  • P(主题 t| 文档 d):文档 d 中分配给主题 t 的单词比例
  • P(word w| topic t):来自 w 的单词在所有文档中对主题 t 的分配比例

3) 考虑所有其他单词及其主题分配,以概率 p(t'|d)*p(w|t') 将主题 T' 重新分配给单词 w

最后一步重复多次,直到我们达到一个稳定状态,主题分配不会进一步改变。然后,根据这些主题分配确定每个文档的主题比例。

如何在Python中实现LDA?

以下是实现LDA算法的步骤:

  1. 收集数据并将其作为输入提供
  2. 预处理数据(删除不必要的数据)
  3. 修改 LDA 分析的数据
  4. 构建和训练 LDA 模型
  5. 分析 LDA 模型结果

在这里,我们有从Twitter收集的输入数据并将其转换为CSV文件,因为社交媒体上的数据是多种多样的,我们可以建立一个有效的模型。

导入 LDA 所需的库

import numpy as np
import pandas as pd 
import re
 
import gensim
from gensim import corpora, models, similarities
from gensim.parsing.preprocessing import STOPWORDS
from nltk.corpus import stopwords

清理数据

规范化空格

def normalize_whitespace(tweet):
    tweet = re.sub('[\s]+', ' ', tweet)
    return tweet
 
text = "         We        are the students    of    Science. "
print("Text Before: ",text)
text = normalize_whitespace(text)
print("Text After: ",text)

输出:

Text Before:    We        are the students    of    Science. 


删除停用词

import nltk
nltk.download('stopwords')
import gensim
from gensim.parsing.preprocessing import STOPWORDS
from nltk.corpus import stopwords
 
stop_words = stopwords.words('english')
 
 
def remove_stopwords(text):
  final_s=""
  text_arr= text.split(" ")                              #splits sentence when space occurs
  print(text_arr)
  for word in text_arr:                             
    if word not in stop_words:                     # if word is not in stopword then append(join) it to string 
      final_s= final_s + word + " "
 
  return final_s 

词干提取和标记化

import nltk
# nltk.download('wordnet')
from nltk.stem import WordNetLemmatizer, SnowballStemmer, PorterStemmer
 
stemmer = PorterStemmer()
 
def tokenize_stemming(text):
    text = re.sub(r'[^\w\s]','',text)
    #replace multiple spaces with one space
    text = re.sub(r'[\s]+',' ',text)
    #transfer text to lowercase
    text = text.lower() 
    # tokenize text
    tokens = re.split(" ", text)
 
    # Remove stop words 
    result = []
    for token in tokens :
        if token not in stop_words and len(token) > 1:
            result.append(stemmer.stem(token))
 
    return result

术语频率 (TF-IDF)

它是术语频率-逆文档频率的缩写,是一种数值统计,旨在反映一个单词对集合或语料库中的文档的重要性。它通常用作加权因素。

corpus_doc2bow_vectors = [dictionary.doc2bow(tok_doc) for tok_doc in tokens]
print("# Term Frequency : ")
corpus_doc2bow_vectors[:5]
 
tfidf_model = models.TfidfModel(corpus_doc2bow_vectors, id2word=dictionary, normalize=False)
corpus_tfidf_vectors = tfidf_model[corpus_doc2bow_vectors]
 
print("\n# TF_IDF: ")
print(corpus_tfidf_vectors[5])

使用 Bag of Words 运行 LDA

lda_model = gensim.models.LdaMulticore(corpus_doc2bow_vectors, num_topics=10, id2word=dictionary, passes=2, workers=2)

使用 TF-IDF 运行 LDA

lda_model_tfidf = gensim.models.LdaMulticore(corpus_tfidf_vectors, num_topics=10, id2word=dictionary, passes=2, workers=4)
for idx, topic in lda_model_tfidf.print_topics(-1):
    print('Topic: {} Word: {}'.format(idx, topic))

主题分类

通过使用 LDA Bag of Words 模型对示例文档进行分类来评估性能 我们将检查测试文档的分类位置。

for index, score in sorted(lda_model[corpus_doc2bow_vectors[1]], key=lambda tup: -1*tup[1]):
    print("\nScore: {}\t \nTopic: {}".format(score, lda_model.print_topic(index, 10)))

通过使用 LDA TF-IDF 模型对样本文档进行分类来评估性能。

for index, score in sorted(lda_model_tfidf[corpus_doc2bow_vectors[1]], key=lambda tup: -1*tup[1]):
    print("\nScore: {}\t \nTopic: {}".format(score, lda_model_tfidf.print_topic(index, 10)))