精华内容
下载资源
问答
  • 用gensim训练LDA模型,进行新闻文本主题分析(有数据集,LDA例子)
  • LDA模型的理解对很多人是一种挑战,尤其是参数估计部分。本文档详细给出了TOTLDA和LDA两个主题概率模型的参数估计需要用到的后验概率的推导过程,并采用了两种方法,对主题概率模型研究人员具有很好的启发意义!...
  • pythond的一个LDA模型的实现
  • lda模型的python实现,算法采用sampling抽样 作者邮箱: 训练和输出文本格式说明 模型训练文件 `train.dat` 用其他软件or算法分词后,再剔除停用词的最后结果文件,显示格式如下:(一行表示一篇文档) 康小姐 寮步...
  • 该文针对用户的视频选择过多、视频转化率较低等问题,提出了一种基于LDA模型的电影推荐方法。首先将视频的评论文本集转化为评论主题词语的三层贝叶斯模型,提取每个视频的评论关键词,再基于目标用户的历史行为...
  • LDA 模型表示文本词汇的概率分布,通过香农信息抽取体现主题的关键词。采用背景词汇聚类及主题词联想的方式将主题词 扩充到待分析文本之外,尝试挖掘文本的主题内涵。模型拟合基于快速 Gibbs 抽样算法进行。实验...
  • 基于LDA模型的微博话题检测,汪进祥,刘念,随着微博用户的不断增长,国外的Twitter和国内的新浪微博已经成为媒体和个人发布信息的重要平台.对于微博这种特殊的文本,通常小于140��
  • 最优LDA模型

    2015-12-13 23:14:08
    LDA的自动找K的方法之一。调试很难,需要尝试很多次。
  • 使用Sk-learn建立LDA模型并使用pyLDAvis绘制主题间距离图 作者:丹麦Anis和Barsha Saha博士 联络方式: 该项目的目的是优化主题模型,以使用网格搜索方法实现最佳拟合。 主题建模是一种有效的无监督机器学习工具...
  • 在本文中,我们研究了潜在狄利克雷分配(LDA)中最佳主题结构和主题之间距离之间的内在联系,并提出了一种基于密度自适应选择最佳LDA模型的方法。 实验表明,该方法无需手动调整主题数即可实现与LDA最佳匹配的性能...
  • LDA模型代码解析

    2018-12-20 11:04:30
    LDA模型代码解析
  • 基于LDA模型的可信社区服务评论排序,刘磊,袁玉宇,在可信社区提供的各项服务中,存在服务的可信度难以评估的问题。为此,提出一种基于LDA模型的可信社区服务评论排序方法。利用LDA
  • lda模型实战篇

    2021-08-10 15:33:09
    1、lda是一种无监督的贝叶斯模型: P(词 | 文档)=P(词 | 主题)P(主题 | 文档) 同一主题下,某个词出现的概率,以及同一文档下,某个主题出现的概率,两个概率的乘积,可以得到某篇文档出现某个词的概率。 2、lda...

    lda简介(理论部分见lda模型理论篇)

    1、lda是一种无监督的贝叶斯模型:
    P(词 | 文档)=P(词 | 主题)P(主题 | 文档)
    同一主题下,某个词出现的概率,以及同一文档下,某个主题出现的概率,两个概率的乘积,可以得到某篇文档出现某个词的概率。
    2、lda用来推测文档的主题分布。它可以将文档集中每篇文档的主题以概率分布的形式给出,从而通过分析一些文档抽取出它们的主题分布后,便可以根据主题分布进行主题聚类或文本分类。
    3、lda 采用词袋模型。所谓词袋模型,是将一篇文档,我们仅考虑一个词汇是否出现,而不考虑其出现的顺序。在词袋模型中,“我喜欢你”和“你喜欢我”是等价的。理论上不适用tfidf,但也可以尝试,与词袋模型相反的一个模型是n-gram,word2vec等考虑了词汇出现的先后顺序
    4、但在一定可以解决一词多义及一义多次
    一个词可以出现在多个主题中:一词多义
    多个词会出现在同一主题中:一义多次

    首先进行分词

    # -*- coding:utf-8 -*-
    # @time  : 11:20
    # @Author:xxma
    import jieba
    import jieba.analyse as ana
    import re
    def cn(text):
        '''
        剔除特殊字符及数字,只保留中文
        :param text:
        :return:
        '''
        str = re.findall(u"[\u4e00-\u9fa5]+", text)
        return str
    
    # 加载停用词
    with open(r'E:\xxma\文本分析\停用词.txt', 'r', encoding='utf-8') as f:
        stopwords = [s.strip() for s in f.readlines()]
    
    def jiebacut(text):
        """
        使用普通分词,sklearn中lda模型的输入,词以逗号分隔
        :param text: 原始文本
        :return:切分后的词,且用空格分隔
        """
        text=str(cn(text)).replace(' ','')
        # jieba.load_userdict(r'dict.txt') #加载自定义词典,本次不设置
        words = [w for w in jieba.lcut(text) if w not in stopwords]  # 剔除停用词
        # print(words,len(words))
        words = [w for w in words if len(words) > 2] #剔除短文本
        return ' '.join(words)
    
    
    def ldajiebacut(text):
        """
        使用普通分词,gensim中lda模型的输入,词以逗号分隔
        :param text: 原始文本
        :return:切分后的词,且用空格分隔
        """
        text=str(cn(text)).replace(' ','')
        # jieba.load_userdict(r'dict.txt') #加载自定义词典,本次不设置
        words = [w for w in jieba.lcut(text) if w not in stopwords]  # 剔除停用词
        # print(words,len(words))
        words = [w for w in words if len(words) > 2] #剔除短文本
        return words
    

    sklearn中的lda实战

    import pandas as pd
    import numpy as np
    from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
    from sklearn.decomposition import LatentDirichletAllocation
    from 文本分析.分词 import jiebacut, tfidfcut
    
    # 加载数据
    df = pd.read_csv(r'contentLDA.txt').drop_duplicates()
    # df = df.iloc[0:1000,:]
    # 分词
    df['cut'] = df['content'].apply(jiebacut)
    df['len'] = df['cut'].apply(len)
    df = df[df['len'] > 0].reset_index(drop=True)
    
    # 使用词频生成词向量
    Vectorizer = CountVectorizer()
    vector = Vectorizer.fit_transform(df['cut'])
    # 使用tfidf生成词向量
    Vectorizer_tfidf = TfidfVectorizer()
    vector_tfidf = Vectorizer_tfidf.fit_transform(df['cut'])
    
    # lda主题模型,需要调参
    # 在实际的应用中,我们需要对K,α,η进行调参。如果是"online"算法,则可能需要对"online"算法的一些参数做调整。
    lda = LatentDirichletAllocation(n_components=2,  # 设置主题个数
                                    max_iter=1000,
                                    doc_topic_prior=0.01,
                                    learning_method='online',  # 将训练样本分批用于更新主题词分布,对内存要求低,但速度较慢
                                    verbose=False,
                                    random_state=0)  # 是否显示迭代过程
    result = lda.fit_transform(vector_tfidf)
    
    # 提取主题对应的词
    topic_words = []
    def print_top_words(model, feature_names, n_top_words):
        # 打印每个主题下权重较高的term
        for topic_idx, topic in enumerate(model.components_):
            # print("Topic #%d:" % topic_idx)
            words = " ".join([feature_names[i]for i in topic.argsort()[:-n_top_words - 1:-1]])
            # print(words)
            topic_words.append(words)
        return topic_words
        # 打印主题-词语分布矩阵
        # print(model.components_)
    
    
    n_top_words = 10
    tf_feature_names = Vectorizer_tfidf.get_feature_names()
    topic_detail = print_top_words(lda, tf_feature_names, n_top_words)
    
    # 获取每个文档的主题
    df_result = pd.DataFrame(result)
    df_result['max'] = df_result.max(axis=1)
    df_result['max_index'] = np.argmax(result,axis=1)
    df_result['topic_words'] = df_result['max_index'].apply(lambda x:topic_detail[x])
    
    # 数据保存
    df_result = df_result[['max','max_index','topic_words']]
    df = pd.DataFrame(df['content'])
    df_save = df.join(df_result)
    df_save.to_csv(r'contentLDA_sklearn_result.csv',sep='\t',index=False)
    
    # 保存模型,以便后期调用
    # joblib.dump(lda,'sklearn_lda.pkl')
    

    gensim中lda实战

    import pandas as pd
    import warnings
    warnings.filterwarnings('ignore')  # 警告扰人,手动封存
    from 文本分析.分词 import jiebacut, tfidfcut, ldajiebacut
    from gensim import corpora, models
    
    # 加载数据
    df = pd.read_csv(r'contentLDA.txt', sep='\t')
    # 分词
    df['cut'] = df['content'].apply(ldajiebacut)
    df['len'] = df['cut'].apply(len)
    df = df[df['len'] > 0].reset_index(drop=True)
    
    # 词向量
    dictionary = corpora.Dictionary(df['cut'])  # 建立词典
    corpus = [dictionary.doc2bow(text) for text in df['cut']]  # 计算文本向量
    # tfidf
    tfidf_model = models.TfidfModel(corpus)
    corpus_tfidf = tfidf_model[corpus]
    
    # lda模型训练(自定义参数:主题个数num_topics,遍历次数passes)
    topics_num = 2
    ldamodel = models.ldamodel.LdaModel(corpus_tfidf
                                        , id2word=dictionary
                                        , num_topics=topics_num
                                        , passes=200
                                        , iterations=1000
                                        , alpha=0.01
                                        ,random_state=0)
    
    # 获取主题对应的词
    topics_num_list = []
    for i in range(topics_num):
        topics = ldamodel.print_topic(topicno=i)
        topics_num_list.append(topics)
    # print(topics_num_list)
    
    # 获取文档对应的主题及对应的词
    corpus_lda = ldamodel[corpus_tfidf]
    topic_id_list = []
    topic_pro_list = []
    for doc in corpus_lda:
        # print(doc)
        topic_id = doc[0][0]
        topic_pro = doc[0][1]
        topic_id_list.append(topic_id)
        topic_pro_list.append(topic_pro)
    
    df['topic']=topic_id_list
    df['topic_pro']=topic_pro_list
    df['topic_words'] = df['topic'].apply(lambda x:topics_num_list[x])
    
    # 保存结果数据
    df = df[['content','topic','topic_pro','topic_words']]
    df.to_csv(r'contentLDA_gensim_result.csv',sep='\t',index=False,encoding='utf-8')
    
    # 保存模型
    # ldamodel.save('gensim_lda.pkl')
    
    # 调用保存好的LDA模型
    # lda = models.ldamodel.LdaModel.load('lda.model')
    
    展开全文
  • 基于知识图谱和LDA模型的社会媒体数据抽取
  • lda模型的另一个实现

    2018-11-15 09:50:12
    lda模型的另一个实现
  • 基于LDA模型特征选择的在线医疗社区文本分类及用户聚类研究.pdf
  • 基于VSM和LDA模型结合的文本分类,王海江,刘晓鸿,自动文本分类是一种管理和利用海量文本数字信息的有效手段。在当今数字文本信息越来越繁杂的情况下,文本分类技术的应用越来越广
  • 基于LDA模型和Doc2vec的学术摘要聚类方法.pdf
  • 1.LDA模型简介(节选自百度百科) LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是...

    1.LDA模型简介节选自百度百科)

    LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档到主题服从多项式分布,主题到词服从多项式分布。
    LDA是一种非监督机器学习技术,可以用来识别大规模文档集(document collection)或语料库(corpus)中潜藏的主题信息。它采用了词袋(bag of words)的方法,这种方法将每一篇文档视为一个词频向量,从而将文本信息转化为了易于建模的数字信息。但是词袋方法没有考虑词与词之间的顺序,这简化了问题的复杂性,同时也为模型的改进提供了契机。每一篇文档代表了一些主题所构成的一个概率分布,而每一个主题又代表了很多单词所构成的一个概率分布。

    2.LDA生成过程节选自百度百科)

    对于语料库中的每篇文档,LDA定义了如下生成过程(generativeprocess):
    1.对每一篇文档,从主题分布中抽取一个主题;
    2.从上述被抽到的主题所对应的单词分布中抽取一个单词;
    3.重复上述过程直至遍历文档中的每一个单词。
    语料库中的每一篇文档与T(通过反复试验等方法事先给定)个主题的一个多项分布 (multinomialdistribution)相对应,将该多项分布记为θ。每个主题又与词汇表(vocabulary)中的V个单词的一个多项分布相对应,将这个多项分布记为φ。

    3.LDA模型实践(Python)

    导入所需库

    import pandas as pd
    import re
    import jieba
    from gensim import corpora, models, similarities
    from pprint import pprint
    import numpy as np
    import time
    

    输入处理数据

    data2 = pd.read_excel('1.xlsx')
    data2_lda = data2['详情']
    
    data2_lda.shape
    data2_lda.drop_duplicates()
    

    机械压缩

    def condense_1(str):
        for i in [1,2]:
            j=0
            while j < len(str)-2*i:
                #判断至少出现了两次
                if str[j:j+i] == str[j+i:j+2*i] and str[j:j+i] == str[j+2*i:j+3*i]:
                    k= j+2*i
                    while k+i<len(str) and str[j:j+i]==str[k+i:k+2*i]:
                        k+=i
                    str =str[:j+i]+str[k+i:]
                j+=1
            i+=1
        for i in [3,4,5]:
            j=0
            while j < len(str)-2*i:
                #判断至少出现了一次
                if str[j:j+i] == str[j+i:j+2*i]:
                    k= j+i
                    while k+i<len(str) and str[j:j+i]==str[k+i:k+2*i]:
                        k+=i
                    str =str[:j+i]+str[k+i:]
                j+=1
            i+=1
        return str
    

    数据筛选

    def chuli_lda(a):#筛选数据
        a.astype('str').apply(lambda x:len(x)).sum() # 统计字符长度
        data1 = a.astype('str').apply(lambda x: condense_1(x))  # 去除重复词
        data1.apply(lambda x: len(x)).sum()
        data2 = data1.apply(lambda x: len(x))
        data3 = pd.concat((data1, data2), axis = 1)  # 合并
        data3.columns = ['详情','字符长度']
        data4 = data3.loc[data3['字符长度'] > 4, '详情']  # 筛选长度大于4的评论
        return data4
    data_lda = chuli_lda(data2_lda)
    data_lda
    

    中文分词

    jieba.load_userdict('热点\建设.txt')
    

    定义停用词过滤函数

    def after_stop(data):
        #添加词典,去掉停用词
        data_cut=data.apply(lambda x:jieba.lcut(str(x)))#lcut(x)表示给x分词,并且返回列表形式
        stopWords=pd.read_csv('stopword.txt',encoding='GB18030',sep='hahaha',header=None,engine='python')
        #此时注意用词里面的,不被作为分隔符
        stopWords=['≮', '≯', '≠', '≮', ' ', '会', '月', '日', '–']+list(stopWords.iloc[:,0])
        #将停用词添加在所有行额第0列中
        data_after_stop=data_cut.apply(lambda x:[i for i in x if i not in stopWords])
        return data_after_stop
    
    data_lda_after_stop = after_stop(data_lda)
    data_lda_after_stop.to_csv('data_lda_after_stop.csv',encoding='utf-8')
    

    加载停用词表

    def load_stopword():#加载停用词表
        f_stop = open('stopword.txt')
        sw = [line.strip() for line in f_stop]
        f_stop.close()
        return sw
    

    主程序

    if __name__ == '__main__':
     
        print('1.初始化停止词列表 ------')
        # 开始的时间
        t_start = time.time()
        # 加载停用词表
        stop_words = load_stopword()
     
        print('2.开始读入语料数据 ------ ')
        # 读入语料库
        f = open('data_lda_after_stop.csv','rb')
        # 语料库分词并去停用词
        texts = [[word for word in line.strip().lower().split() if word not in stop_words] for line in f]
     
        print('读入语料数据完成,用时%.3f秒' % (time.time() - t_start))
        f.close()
        M = len(texts)
        print('文本数目:%d个' % M)
     
        print('3.正在建立词典 ------')
      
        print ('4.正在计算文本向量 ------')
        # 转换文本数据为索引,并计数
        corpus = [dictionary.doc2bow(text) for text in texts]
     
        print ('5.正在计算文档TF-IDF ------')
        t_start = time.time()
        # 计算tf-idf值
        corpus_tfidf = models.TfidfModel(corpus)
        print ('建立文档TF-IDF完成,用时%.3f秒' % (time.time() - t_start))
     
        print ('6.LDA模型拟合推断 ------')
        # 训练模型
        num_topics = 30
        t_start = time.time()
        lda = models.LdaModel(corpus_tfidf, num_topics=num_topics, id2word=dictionary,
                                alpha=0.01, eta=0.01, minimum_probability=0.001,
                                chunksize = 100, passes = 1)
        print('LDA模型完成,训练时间为\t%.3f秒' % (time.time() - t_start))
     
        # 随机打印某10个文档的主题
        num_show_topic = 10  # 每个文档显示前几个主题
        print('7.结果:10个文档的主题分布:--')
        doc_topics = lda.get_document_topics(corpus_tfidf)  # 所有文档的主题分布
        idx = np.arange(M)
        np.random.shuffle(idx)
        idx = idx[:10]
        for i in idx:
            topic = np.array(doc_topics[i])
            topic_distribute = np.array(topic[:, 1])
            # print topic_distribute
            topic_idx = topic_distribute.argsort()[:-num_show_topic-1:-1]
            print ('第%d个文档的前%d个主题:' % (i, num_show_topic)), topic_idx
            print(topic_distribute[topic_idx])
     
        num_show_term = 7   # 每个主题显示几个词
        print('8.结果:每个主题的词分布:--')
        for topic_id in range(num_topics):
            print('主题#%d:\t' % topic_id)
            term_distribute_all = lda.get_topic_terms(topicid=topic_id)
            term_distribute = term_distribute_all[:num_show_term]
            term_distribute = np.array(term_distribute)
            term_id = term_distribute[:, 0].astype(np.int)
            print('词:\t',)
            for t in term_id:
                print(dictionary.id2token[t],)
            print('\n概率:\t', term_distribute[:, 1])
    

    运行结果展示
    在这里插入图片描述在这里插入图片描述

    展开全文
  • Python实现LDA主题模型以及模型可视化 - 采用jieba进行数据处理 - 采用gensim构建主题模型 - 采用pyLDAvis可视化主题模型
  • 基于LDA模型的用户画像构建 运行配置 请同时配置python2 与 python3 简介 "主题模型"是对文本中隐含主题的一种建模方法。 每个主题其实是词表上单词的概率分布。 常见的主题模型有3种: PLSA LDA L-LDA LDA 包含“词...
  • 之前在公众号里分享过好几次LDA话题模型的,但考虑的问题都比较简单。这次我将分享在这个notebook中,将会对以下问题进行实战:提取话题的关键词gridsearch寻找最佳模型参数可视化话题模型预测新输入的文本的话题...

    2019 Stata & Python 实证计量与爬虫分析暑期工作坊还有几天就要开始了。之前在公众号里分享过好几次LDA话题模型的,但考虑的问题都比较简单。这次我将分享在这个notebook中,将会对以下问题进行实战:

    提取话题的关键词

    gridsearch寻找最佳模型参数

    可视化话题模型

    预测新输入的文本的话题

    如何查看话题的特征词组

    如何获得每个话题的最重要的n个特征词

    1.导入数据

    这里我们使用的20newsgroups数据集

    import

    pandas

    as

    pd

    df

    =

    pd

    .

    read_json

    (

    'newsgroups.json'

    )

    df

    .

    head

    ()

    查看target_names有哪些类别

    df

    .

    target_names

    .

    unique

    ()

    Run

    array

    ([

    'rec.autos'

    ,

    'comp.sys.mac.hardware'

    ,

    'rec.motorcycles'

    ,

    'misc.forsale'

    ,

    'comp.os.ms-windows.misc'

    ,

    'alt.atheism'

    ,

    'comp.graphics'

    ,

    'rec.sport.baseball'

    ,

    'rec.sport.hockey'

    ,

    'sci.electronics'

    ,

    'sci.space'

    ,

    'talk.politics.misc'

    ,

    'sci.med'

    ,

    'talk.politics.mideast'

    ,

    'soc.religion.christian'

    ,

    'comp.windows.x'

    ,

    'comp.sys.ibm.pc.hardware'

    ,

    'talk.politics.guns'

    ,

    'talk.religion.misc'

    ,

    'sci.crypt'

    ],

    dtype

    =

    object

    )

    2.英文清洗数据

    使用正则表达式去除邮件和换行等多余空白字符

    使用gensim库的simple_preprocess分词,得到词语列表

    注意:

    nltk和spacy安装配置比较麻烦,可以看这篇文章。

    自然语言处理库nltk、spacy安装及配置方法其中nltk语料库和spacy的英文模型均已放置在教程文件夹内~

    import

    nltk

    import

    gensim

    from

    nltk

    import

    pos_tag

    import

    re

    from

    nltk

    .

    corpus

    import

    stopwords

    #导入spacy的模型

    nlp

    =

    spacy

    .

    load

    (

    'en_core_web_sm'

    ,

    disable

    =[

    'parser'

    ,

    'ner'

    ])

    def

    clean_text

    (

    text

    ,

    allowed_postags

    =[

    'NOUN'

    ,

    'ADJ'

    ,

    'VERB'

    ,

    'ADV'

    ]):

    text

    =

    re

    .

    sub

    (

    '\S*@\S*\s?'

    ,

    ''

    ,

    text

    )

    #去除邮件

    text

    =

    re

    .

    sub

    (

    '\s+'

    ,

    ' '

    ,

    text

    )

    #将连续空格、换行、制表符 替换为 空格

    #deacc=True可以将某些非英文字母转化为英文字母,例如

    #"Šéf chomutovských komunistů dostal poštou bílý prášek"转化为

    #u'Sef chomutovskych komunistu dostal postou bily prasek'

    words

    =

    gensim

    .

    utils

    .

    simple_preprocess

    (

    text

    ,

    deacc

    =

    True

    )

    #可以在此处加入去停词操作

    stpwords

    =

    stopwords

    .

    words

    (

    'english'

    )

    #保留词性为'NOUN', 'ADJ', 'VERB', 'ADV'词语

    doc

    =

    nlp

    (

    ' '

    .

    join

    (

    words

    ))

    text

    =

    " "

    .

    join

    ([

    token

    .

    lemma_

    if

    token

    .

    lemma_

    not

    in

    [

    '-PRON-'

    ]

    else

    ''

    for

    token

    in

    doc

    if

    token

    .

    pos_

    in

    allowed_postags

    ])

    return

    text

    test

    =

    "From: lerxst@wam.umd.edu (where's my thing)\nSubject: WHAT car is this!?\nNntp-Posting-Host: rac3.wam.umd.edu\nOrganization: University of Maryland, College Park\nLines: 15\n\n I was wondering if anyone out there could enlighten me on this car I saw\nthe other day. It was a 2-door sports car, looked to be from the late 60s/\nearly 70s. It was called a Bricklin. The doors were really small. In addition,\nthe front bumper was separate from the rest of the body. This is \nall I know. If anyone can tellme a model name, engine specs, years\nof production, where this car is made, history, or whatever info you\nhave on this funky looking car, please e-mail.\n\nThanks,\n- IL\n ---- brought to you by your neighborhood Lerxst ----\n\n\n\n\n"

    clean_text

    (

    test

    )

    Run

    'where thing subject car be nntp post host rac wam umd edu organization university maryland college park line be wonder anyone out there could enlighten car see other day be door sport car look be late early be call bricklin door be really small addition front bumper be separate rest body be know anyone can tellme model name engine spec year production where car be make history info have funky look car mail thank bring neighborhood lerxst'

    将将数据content列进行批处理(数据清洗clean_text)

    df

    .

    content

    =

    df

    .

    content

    .

    apply

    (

    clean_text

    )

    df

    .

    head

    ()

    3. 构建文档词频矩阵 document-word matrix

    from

    sklearn

    .

    feature_extraction

    .

    text

    import

    TfidfVectorizer

    ,

    CountVectorizer

    #vectorizer = TfidfVectorizer(min_df=10)#单词至少出现在10个文档中

    vectorizer

    =

    CountVectorizer

    (

    analyzer

    =

    'word'

    ,

    min_df

    =

    10

    ,

    # minimum reqd occurences of a word

    lowercase

    =

    True

    ,

    # convert all words to lowercase

    token_pattern

    =

    '[a-zA-Z0-9]{3,}'

    ,

    # num chars > 3

    # max_features=50000, # max number of uniq words

    )

    data_vectorized

    =

    vectorizer

    .

    fit_transform

    (

    df

    .

    content

    )

    检查数据的稀疏性,

    data_dense

    =

    data_vectorized

    .

    todense

    ()

    # Compute Sparsicity = Percentage of Non-Zero cells

    print

    (

    "Sparsicity: "

    ,

    ((

    data_dense

    >

    0

    ).

    sum

    ()/

    data_dense

    .

    size

    )*

    100

    ,

    '%'

    )

    Run

    Sparsicity

    :

    0.9138563473570427

    %

    4.构建LDA模型

    使用sklearn库的LatentDirichletAllocation

    from

    sklearn

    .

    decomposition

    import

    LatentDirichletAllocation

    # 构建LDA话题模型

    lda_model

    =

    LatentDirichletAllocation

    (

    n_components

    =

    20

    )

    # 话题数

    lda_output

    =

    lda_model

    .

    fit_transform

    (

    data_vectorized

    )

    模型表现

    # 越高越好

    print

    (

    lda_model

    .

    score

    (

    data_vectorized

    ))

    #训练好的模型的参数

    print

    (

    lda_model

    .

    get_params

    ())

    Run

    -

    11868684.751381714

    {

    'batch_size'

    :

    128

    ,

    'doc_topic_prior'

    :

    None

    ,

    'evaluate_every'

    :

    -

    1

    ,

    'learning_decay'

    :

    0.7

    ,

    'learning_method'

    :

    'batch'

    ,

    'learning_offset'

    :

    10.0

    ,

    'max_doc_update_iter'

    :

    100

    ,

    'max_iter'

    :

    10

    ,

    'mean_change_tol'

    :

    0.001

    ,

    'n_components'

    :

    20

    ,

    'n_jobs'

    :

    None

    ,

    'perp_tol'

    :

    0.1

    ,

    'random_state'

    :

    None

    ,

    'topic_word_prior'

    :

    None

    ,

    'total_samples'

    :

    1000000.0

    ,

    'verbose'

    :

    0

    }

    5. 如何找到最佳的话题数

    LatentDirichletAllocation中有很多参数,调整参数会使得结果发生变化。为了训练出更好的模型,这里我们使用ncomponents和learningdecay这两个参数作为示范,设置这两个参数可能的取值范围。

    运行时间 半个小时~

    from

    sklearn

    .

    model_selection

    import

    GridSearchCV

    设置参数搜寻的范围

    search_params

    {

    'n_components'

    :

    [

    10

    ,

    15

    ,

    20

    ,

    25

    ,

    30

    ],

    'learning_decay'

    :

    [.

    5

    ,

    .

    7

    ,

    .

    9

    ]}

    初始化LDA模型

    lda

    LatentDirichletAllocation

    ()

    初始化GridSearchCV

    model

    GridSearchCV

    (

    lda

    ,

    param_grid

    search_params

    )

    训练LDA模型

    model

    .

    fit

    (

    data_vectorized

    )

    查看模型参数

    model

    .

    cvresults

    Run

    {

    'mean_fit_time'

    :

    array

    ([

    76.23844155

    ,

    78.47619971

    ,

    75.65877469

    ,

    92.04278994

    ,

    92.47375035

    ,

    70.50102162

    ,

    77.17208759

    ,

    77.42245611

    ,

    78.51173854

    ,

    80.36060111

    ,

    64.35273759

    ,

    80.74369526

    ,

    78.33191927

    ,

    97.60522366

    ,

    91.52556197

    ]),

    'std_fit_time'

    :

    array

    ([

    1.90773724

    ,

    6.00546298

    ,

    2.90480388

    ,

    10.82104708

    ,

    2.15837996

    ,

    0.91492716

    ,

    1.78299082

    ,

    0.99124146

    ,

    0.88202007

    ,

    2.52887488

    ,

    1.42895102

    ,

    3.4966494

    ,

    4.10921772

    ,

    8.57965772

    ,

    2.97772162

    ]),

    'mean_score_time'

    :

    array

    ([

    3.03948617

    ,

    3.12327973

    ,

    3.17385236

    ,

    4.1181256

    ,

    4.14796472

    ,

    2.80464379

    ,

    3.00497603

    ,

    3.18396346

    ,

    3.29176935

    ,

    3.34573205

    ,

    2.60685007

    ,

    3.05136299

    ,

    3.39874609

    ,

    3.77345729

    ,

    4.19327569

    ]),

    'std_score_time'

    :

    array

    ([

    0.29957093

    ,

    0.0616576

    ,

    0.13170509

    ,

    0.4152717

    ,

    0.58759639

    ,

    0.05777709

    ,

    0.17347846

    ,

    0.06664403

    ,

    0.13021069

    ,

    0.12982755

    ,

    0.06256295

    ,

    0.13255927

    ,

    0.43057235

    ,

    0.29978059

    ,

    0.44248399

    ]),

    'param_learning_decay'

    :

    masked_array

    (

    data

    =[

    0.5

    ,

    0.5

    ,

    0.5

    ,

    0.5

    ,

    0.5

    ,

    0.7

    ,

    0.7

    ,

    0.7

    ,

    0.7

    ,

    0.7

    ,

    0.9

    ,

    0.9

    ,

    0.9

    ,

    0.9

    ,

    0.9

    ],

    mask

    =[

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ],

    fill_value

    =

    '?'

    ,

    dtype

    =

    object

    ),

    'param_n_components'

    :

    masked_array

    (

    data

    =[

    10

    ,

    15

    ,

    20

    ,

    25

    ,

    30

    ,

    10

    ,

    15

    ,

    20

    ,

    25

    ,

    30

    ,

    10

    ,

    15

    ,

    20

    ,

    25

    ,

    30

    ],

    mask

    =[

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ,

    False

    ],

    fill_value

    =

    '?'

    ,

    dtype

    =

    object

    ),

    'params'

    :

    [{

    'learning_decay'

    :

    0.5

    ,

    'n_components'

    :

    10

    },

    {

    'learning_decay'

    :

    0.5

    ,

    'n_components'

    :

    15

    },

    {

    'learning_decay'

    :

    0.5

    ,

    'n_components'

    :

    20

    },

    {

    'learning_decay'

    :

    0.5

    ,

    'n_components'

    :

    25

    },

    {

    'learning_decay'

    :

    0.5

    ,

    'n_components'

    :

    30

    },

    {

    'learning_decay'

    :

    0.7

    ,

    'n_components'

    :

    10

    },

    {

    'learning_decay'

    :

    0.7

    ,

    'n_components'

    :

    15

    },

    {

    'learning_decay'

    :

    0.7

    ,

    'n_components'

    :

    20

    },

    {

    'learning_decay'

    :

    0.7

    ,

    'n_components'

    :

    25

    },

    {

    'learning_decay'

    :

    0.7

    ,

    'n_components'

    :

    30

    },

    {

    'learning_decay'

    :

    0.9

    ,

    'n_components'

    :

    10

    },

    {

    'learning_decay'

    :

    0.9

    ,

    'n_components'

    :

    15

    },

    {

    'learning_decay'

    :

    0.9

    ,

    'n_components'

    :

    20

    },

    {

    'learning_decay'

    :

    0.9

    ,

    'n_components'

    :

    25

    },

    {

    'learning_decay'

    :

    0.9

    ,

    'n_components'

    :

    30

    }],

    'split0_test_score'

    :

    array

    ([-

    3874856.42190824

    ,

    -

    3881092.28265286

    ,

    -

    3905854.25463761

    ,

    -

    3933237.60526826

    ,

    -

    3945083.8541135

    ,

    -

    3873412.75021688

    ,

    -

    3873882.90565526

    ,

    -

    3911751.31895979

    ,

    -

    3921171.68942096

    ,

    -

    3949413.2598192

    ,

    -

    3876577.95159756

    ,

    -

    3886340.65539402

    ,

    -

    3896362.39547871

    ,

    -

    3926181.21965185

    ,

    -

    3950533.84046263

    ]),

    'split1_test_score'

    :

    array

    ([-

    4272638.34477011

    ,

    -

    4294980.87988645

    ,

    -

    4310841.4440567

    ,

    -

    4336244.55854965

    ,

    -

    4341014.91687451

    ,

    -

    4279229.66282939

    ,

    -

    4302326.23456232

    ,

    -

    4317599.83998105

    ,

    -

    4325020.1483235

    ,

    -

    4338663.90026249

    ,

    -

    4284095.2173055

    ,

    -

    4294941.56802545

    ,

    -

    4299746.08581904

    ,

    -

    4331262.03558289

    ,

    -

    4338027.82208097

    ]),

    'split2_test_score'

    :

    array

    ([-

    4200870.80494405

    ,

    -

    4219318.82663835

    ,

    -

    4222122.82436968

    ,

    -

    4237003.85511169

    ,

    -

    4258352.71194228

    ,

    -

    4192824.54480934

    ,

    -

    4200329.40329793

    ,

    -

    4231613.93138699

    ,

    -

    4258255.99302186

    ,

    -

    4270014.58888107

    ,

    -

    4199499.64459735

    ,

    -

    4209918.86599275

    ,

    -

    4230265.99859102

    ,

    -

    4247913.06952193

    ,

    -

    4256046.3237088

    ]),

    'mean_test_score'

    :

    array

    ([-

    4116100.53270373

    ,

    -

    4131775.17089196

    ,

    -

    4146251.59136724

    ,

    -

    4168807.85000785

    ,

    -

    4181462.93317874

    ,

    -

    4115134.28591336

    ,

    -

    4125490.60725673

    ,

    -

    4153633.64919084

    ,

    -

    4168127.44754368

    ,

    -

    4186009.66931221

    ,

    -

    4120036.0842904

    ,

    -

    4130378.79165891

    ,

    -

    4142103.10465406

    ,

    -

    4168430.69488042

    ,

    -

    4181515.57804474

    ]),

    'std_test_score'

    :

    array

    ([

    173105.26046897

    ,

    179953.68165447

    ,

    173824.10245002

    ,

    171450.68036995

    ,

    170539.38663682

    ,

    174546.8275931

    ,

    182743.94823856

    ,

    174623.71594324

    ,

    176761.14575071

    ,

    169651.81366214

    ,

    175603.01769822

    ,

    176039.50084949

    ,

    176087.37700361

    ,

    174665.17839821

    ,

    166743.56843518

    ]),

    'rank_test_score'

    :

    array

    ([

    2

    ,

    6

    ,

    8

    ,

    12

    ,

    13

    ,

    1

    ,

    4

    ,

    9

    ,

    10

    ,

    15

    ,

    3

    ,

    5

    ,

    7

    ,

    11

    ,

    14

    ],

    dtype

    =

    int32

    )}

    输出参数搜寻出模型的效果并将其可视化

    import

    matplotlib

    .

    pyplot

    as

    plt

    # Get Log Likelyhoods from Grid Search Output

    n_topics

    =

    [

    10

    ,

    15

    ,

    20

    ,

    25

    ,

    30

    ]

    log_likelyhoods_5

    =

    model

    .

    cv_results_

    [

    'mean_test_score'

    ][

    model

    .

    cv_results_

    [

    'param_learning_decay'

    ]==

    0.5

    ]

    log_likelyhoods_7

    =

    model

    .

    cv_results_

    [

    'mean_test_score'

    ][

    model

    .

    cv_results_

    [

    'param_learning_decay'

    ]==

    0.7

    ]

    log_likelyhoods_9

    =

    model

    .

    cv_results_

    [

    'mean_test_score'

    ][

    model

    .

    cv_results_

    [

    'param_learning_decay'

    ]==

    0.9

    ]

    # Show graph

    plt

    .

    figure

    (

    figsize

    =(

    12

    ,

    8

    ))

    plt

    .

    plot

    (

    n_topics

    ,

    log_likelyhoods_5

    ,

    label

    =

    '0.5'

    )

    plt

    .

    plot

    (

    n_topics

    ,

    log_likelyhoods_7

    ,

    label

    =

    '0.7'

    )

    plt

    .

    plot

    (

    n_topics

    ,

    log_likelyhoods_9

    ,

    label

    =

    '0.9'

    )

    plt

    .

    title

    (

    "Choosing Optimal LDA Model"

    )

    plt

    .

    xlabel

    (

    "Num Topics"

    )

    plt

    .

    ylabel

    (

    "Log Likelyhood Scores"

    )

    plt

    .

    legend

    (

    title

    =

    'Learning decay'

    ,

    loc

    =

    'best'

    )

    plt

    .

    show

    ()

    #最佳话题模型

    best_lda_model

    =

    model

    .

    best_estimator_

    print

    (

    "Best Model's Params: "

    ,

    model

    .

    best_params_

    )

    print

    (

    "Best Log Likelihood Score: "

    ,

    model

    .

    best_score_

    )

    Run

    Best

    Model

    's Params: {'

    learning_decay

    ': 0.7, '

    n_components

    ': 10}

    Best Log Likelihood Score: -4115134.285913357

    6. 如何查看每个文档的话题信息

    LDA会给每个文档分配一个话题分布,其中概率最大的话题最能代表该文档

    import

    numpy

    as

    np

    # 构建文档-词频矩阵

    lda_output

    =

    best_lda_model

    .

    transform

    (

    data_vectorized

    )

    # 列名

    topicnames

    =

    [

    "Topic"

    +

    str

    (

    i

    )

    for

    i

    in

    range

    (

    best_lda_model

    .

    n_components

    )]

    # 行索引名

    docnames

    =

    [

    "Doc"

    +

    str

    (

    i

    )

    for

    i

    in

    range

    (

    len

    (

    df

    .

    content

    ))]

    # 转化为pd.DataFrame

    df_document_topic

    =

    pd

    .

    DataFrame

    (

    np

    .

    round

    (

    lda_output

    ,

    2

    ),

    columns

    =

    topicnames

    ,

    index

    =

    docnames

    )

    # Get dominant topic for each document

    dominant_topic

    =

    np

    .

    argmax

    (

    df_document_topic

    .

    values

    ,

    axis

    =

    1

    )

    df_document_topic

    [

    'dominant_topic'

    ]

    =

    dominant_topic

    # Styling

    def

    color_green

    (

    val

    ):

    color

    =

    'green'

    if

    val

    >

    .

    1

    else

    'black'

    return

    'color: {col}'

    .

    format

    (

    col

    =

    color

    )

    def

    make_bold

    (

    val

    ):

    weight

    =

    700

    if

    val

    >

    .

    1

    else

    400

    return

    'font-weight: {weight}'

    .

    format

    (

    weight

    =

    weight

    )

    # Apply Style

    df_document_topics

    =

    df_document_topic

    .

    sample

    (

    10

    ).

    style

    .

    applymap

    (

    color_green

    ).

    applymap

    (

    make_bold

    )

    df_document_topics

    查看话题分布情况

    df_topic_distribution

    =

    df_document_topic

    [

    'dominant_topic'

    ].

    value_counts

    ().

    reset_index

    (

    name

    =

    "Num Documents"

    )

    df_topic_distribution

    .

    columns

    =

    [

    'Topic Num'

    ,

    'Num Documents'

    ]

    df_topic_distribution

    7.如何可视化LDA

    pyLDAvis可视化话题

    import

    pyLDAvis

    import

    pyLDAvis

    .

    sklearn

    #在notebook中显示

    pyLDAvis

    .

    enable_notebook

    ()

    panel

    =

    pyLDAvis

    .

    sklearn

    .

    prepare

    (

    best_lda_model

    ,

    #训练好的lda模型

    data_vectorized

    ,#训练库语料的词语特征空间(即

    Tfidfvecterizer

    或者

    CounterVecterizer

    )

    vectorizer

    )

    panel

    由于网络问题,这里插不了gif动图,我放之前的文章链接,大家可以看看可视化效果。手把手教你学会LDA话题模型可视化pyLDAvis库

    8. 如何查看话题的特征词组

    每个话题都是由带有权重的词组进行表征,是一个二维空间

    # 话题-关键词矩阵(Topic-Keyword Matrix)

    df_topic_keywords

    =

    pd

    .

    DataFrame

    (

    best_lda_model

    .

    components_

    )

    # 重新分配dataframe中的列名和行索引名

    df_topic_keywords

    .

    columns

    =

    vectorizer

    .

    get_feature_names

    ()

    #训练集的词语空间的词表

    df_topic_keywords

    .

    index

    =

    topicnames

    df_topic_keywords

    9.如何获得每个话题的最重要的n个特征词

    # 显示每个话题最重要的n个词语

    def

    show_topics

    (

    vectorizer

    =

    vectorizer

    ,

    lda_model

    =

    lda_model

    ,

    top_n

    =

    20

    ):

    keywords

    =

    np

    .

    array

    (

    vectorizer

    .

    get_feature_names

    ())

    topic_keywords

    =

    []

    #话题-词语权重矩阵

    for

    topic_weights

    in

    lda_model

    .

    components_

    :

    #获得权重最大的top_n词语的权重向量

    top_keyword_locs

    =

    (-

    topic_weights

    ).

    argsort

    ()[:

    top_n

    ]

    #在keywords中找到对于的关键词

    topic_keywords

    .

    append

    (

    keywords

    .

    take

    (

    top_keyword_locs

    ))

    return

    topic_keywords

    topic_keywords

    =

    show_topics

    (

    vectorizer

    =

    vectorizer

    ,

    lda_model

    =

    best_lda_model

    ,

    top_n

    =

    10

    )

    #最重要的10个词语

    df_topic_keywords

    =

    pd

    .

    DataFrame

    (

    topic_keywords

    )

    df_topic_keywords

    .

    columns

    =

    [

    'Word '

    +

    str

    (

    i

    )

    for

    i

    in

    range

    (

    df_topic_keywords

    .

    shape

    [

    1

    ])]

    df_topic_keywords

    .

    index

    =

    [

    'Topic '

    +

    str

    (

    i

    )

    for

    i

    in

    range

    (

    df_topic_keywords

    .

    shape

    [

    0

    ])]

    df_topic_keywords

    10. 如何对新文本进行话题预测

    给训练好的模型输入新文本,预测该文本的话题

    Define function to predict topic for a given text document.

    #nlp = spacy.load('en', disable=['parser', 'ner'])

    def

    predict_topic

    (

    texts

    ,

    nlp

    nlp

    ):

    #清洗数据,如提出空格、邮箱、剔除无意义的词语、保留信息量比较大的词性

    cleaned_texts

    =

    []

    for

    text

    in

    texts

    :

    cleaned_texts

    .

    append

    (

    clean_text

    (

    text

    ))

    doc_term_matrix

    =

    vectorizer

    .

    transform

    (

    cleaned_texts

    )

    #LDA transform

    topic_term_prob_matrix

    =

    best_lda_model

    .

    transform

    (

    doc_term_matrix

    )

    #话题

    topic_index

    =

    np

    .

    argmax

    (

    topic_term_prob_matrix

    )

    topic_word

    =

    df_topic_keywords

    .

    iloc

    [

    topic_index

    ,

    :].

    values

    .

    tolist

    ()

    return

    topic_index

    ,

    topic_word

    ,

    topic_term_prob_matrix

    #预测

    mytext

    =

    [

    "Some text about christianity and bible"

    ]

    topic_index

    ,

    topic_word

    ,

    topic_term_prob_matrix

    =

    predict_topic

    (

    mytext

    )

    print

    (

    "该文本的所属的话题是Topic"

    ,

    topic_index

    )

    print

    (

    "该话题的特征词 "

    ,

    topic_word

    )

    print

    (

    "特征词的权重分布情况 "

    ,

    topic_term_prob_matrix

    )

    Run

    该文本的所属的话题是

    Topic

    5

    该话题的特征词

    [

    'not'

    ,

    'have'

    ,

    'max'

    ,

    'god'

    ,

    'say'

    ,

    'can'

    ,

    'there'

    ,

    'write'

    ,

    'christian'

    ,

    'would'

    ]

    特征词的权重分布情况

    [[

    0.02500225

    0.025

    0.02500547

    0.02500543

    0.02500001

    0.7749855

    0.02500082

    0.02500052

    0.025

    0.025

    ]]

    展开全文
  • LDA模型理解

    万次阅读 多人点赞 2018-07-16 16:08:21
    转载声明:这篇博客转自七月在线创始人v_JULY_v的博客0 前言 印象中,最开始听说“LDA”这个名词,是缘于rickjin在2013年3月写的一个LDA科普系列,叫LDA数学八卦,我当时一直想看来着,记得还打印过一次,但不知是...

    转载声明:这篇博客转自七月在线创始人v_JULY_v的博客


    0 前言

        印象中,最开始听说“LDA”这个名词,是缘于rickjin在2013年3月写的一个LDA科普系列,叫LDA数学八卦,我当时一直想看来着,记得还打印过一次,但不知是因为这篇文档的前序铺垫太长(现在才意识到这些“铺垫”都是深刻理解LDA 的基础,但如果没有人帮助初学者提纲挈领、把握主次、理清思路,则很容易陷入LDA的细枝末节之中),还是因为其中的数学推导细节太多,导致一直没有完整看完过。

        2013年12月,在我组织的Machine Learning读书会第8期上,@夏粉_百度 讲机器学习中排序学习的理论和算法研究,@沈醉2011 则讲主题模型的理解。又一次碰到了主题模型,当时貌似只记得沈博讲了一个汪峰写歌词的例子,依然没有理解LDA到底是怎样一个东西(但理解了LDA之后,再看沈博主题模型的PPT会很赞)。

        直到昨日下午,机器学习班 第12次课上,邹讲完LDA之后,才真正明白LDA原来是那么一个东东!上完课后,趁热打铁,再次看LDA数学八卦,发现以前看不下去的文档再看时竟然一路都比较顺畅,一口气看完大部。看完大部后,思路清晰了,知道理解LDA,可以分为下述5个步骤:

    1. 一个函数:gamma函数
    2. 四个分布:二项分布、多项分布、beta分布、Dirichlet分布
    3. 一个概念和一个理念:共轭先验和贝叶斯框架
    4. 两个模型:pLSA、LDA(在本文第4 部分阐述)
    5. 一个采样:Gibbs采样

        本文便按照上述5个步骤来阐述,希望读者看完本文后,能对LDA有个尽量清晰完整的了解。同时,本文基于邹讲LDA的PPT、rickjin的LDA数学八卦及其它参考资料写就,可以定义为一篇学习笔记或课程笔记,当然,后续不断加入了很多自己的理解。若有任何问题,欢迎随时于本文评论下指出,thanks。


    1 gamma函数

    1.0 整体把握LDA

        关于LDA有两种含义,一种是线性判别分析(Linear Discriminant Analysis),一种是概率主题模型:隐含狄利克雷分布(Latent Dirichlet Allocation,简称LDA),本文讲后者。

        另外,我先简单说下LDA的整体思想,不然我怕你看了半天,铺了太长的前奏,却依然因没见到LDA的影子而显得“心浮气躁”,导致不想再继续看下去。所以,先给你吃一颗定心丸,明白整体框架后,咱们再一步步抽丝剥茧,展开来论述。

        按照wiki上的介绍,LDA由Blei, David M.、Ng, Andrew Y.、Jordan于2003年提出,是一种主题模型,它可以将文档集 中每篇文档的主题以概率分布的形式给出,从而通过分析一些文档抽取出它们的主题(分布)出来后,便可以根据主题(分布)进行主题聚类或文本分类。同时,它是一种典型的词袋模型,即一篇文档是由一组词构成,词与词之间没有先后顺序的关系。

        此外,一篇文档可以包含多个主题,文档中每一个词都由其中的一个主题生成。

        人类是怎么生成文档的呢?LDA的这三位作者在原始论文中给了一个简单的例子。比如假设事先给定了这几个主题:Arts、Budgets、Children、Education,然后通过学习训练,获取每个主题Topic对应的词语。如下图所示:

     

        然后以一定的概率选取上述某个主题,再以一定的概率选取那个主题下的某个单词,不断的重复这两步,最终生成如下图所示的一篇文章(其中不同颜色的词语分别对应上图中不同主题下的词):

      

        而当我们看到一篇文章后,往往喜欢推测这篇文章是如何生成的,我们可能会认为作者先确定这篇文章的几个主题,然后围绕这几个主题遣词造句,表达成文。
        LDA就是要干这事: 根据给定的一篇文档,推测其主题分布
        通俗来说,可以假定认为 人类是根据上述文档生成过程写成了各种各样的文章,现在某小撮人想让计算机利用LDA干一件事:你计算机给我推测分析网络上各篇文章分别都写了些啥主题,且各篇文章中各个主题出现的概率大小(主题分布)是啥
        然,就是这么一个看似普通的LDA,一度吓退了不少想深入探究其内部原理的初学者。难在哪呢,难就难在LDA内部涉及到的数学知识点太多了。
        在LDA模型中,一篇文档生成的方式如下:
    • 从狄利克雷分布中取样生成文档 i 的主题分布
    • 从主题的多项式分布中取样生成文档i第 j 个词的主题
    • 从狄利克雷分布中取样生成主题对应的词语分布
    • 从词语的多项式分布中采样最终生成词语

        其中,类似Beta分布是二项式分布的共轭先验概率分布,而狄利克雷分布(Dirichlet分布)是多项式分布的共轭先验概率分布。

        此外,LDA的图模型结构如下图所示(类似贝叶斯网络结构):

        恩,不错,短短6句话整体概括了整个LDA的主体思想!但也就是上面短短6句话,却接连不断或重复出现了二项分布、多项式分布、beta分布、狄利克雷分布(Dirichlet分布)、共轭先验概率分布、取样,那么请问,这些都是啥呢?

        这里先简单解释下二项分布、多项分布、beta分布、Dirichlet 分布这4个分布。

    •  二项分布(Binomial distribution)
        二项分布是从伯努利分布推进的。伯努利分布,又称两点分布或0-1分布,是一个离散型的随机分布,其中的随机变量只有两类取值,非正即负{+,-}。而二项分布即重复n次的伯努利试验,记为  。简言之,只做一次实验,是伯努利分布,重复做了n次,是二项分布。二项分布的概率密度函数为:

        
        对于k = 0, 1, 2, ..., n,其中的 是二项式系数(这就是二项分布的名称的由来),又记为 。回想起高中所学的那丁点概率知识了么:想必你当年一定死记过这个二项式系数 就是
    • 多项分布,是二项分布扩展到多维的情况
        多项分布是指单次试验中的随机变量的取值不再是0-1的,而是有多种离散值可能(1,2,3...,k)。比如投掷6个面的骰子实验,N次实验结果服从K=6的多项分布。其中

        多项分布的概率密度函数为:
    • Beta分布,二项分布的共轭先验分布
        给定参数 ,取值范围为[0,1]的随机变量 x 的概率密度函数:
        其中:
    。 
       注: 便是所谓的gamma函数,下文会具体阐述。
    • Dirichlet分布,是beta分布在高维度上的推广
        Dirichlet分布的的密度函数形式跟beta分布的密度函数如出一辙:
        其中
        至此,我们可以看到 二项分布和多项分布很相似, Beta分布和Dirichlet 分布很相似,而至于 Beta分布是二项式分布的共轭先验概率分布,而狄利克雷分布 (Dirichlet分布)是多项式分布的共轭先验概率分布 这点在下文中说明。

        OK,接下来,咱们就按照本文开头所说的思路:“一个函数:gamma函数,四个分布:二项分布、多项分布、beta分布、Dirichlet分布,外加一个概念和一个理念:共轭先验和贝叶斯框架,两个模型:pLSA、LDA(文档-主题,主题-词语),一个采样:Gibbs采样”一步步详细阐述,争取给读者一个尽量清晰完整的LDA。

        (当然,如果你不想深究背后的细节原理,只想整体把握LDA的主体思想,可直接跳到本文第4 部分,看完第4部分后,若还是想深究背后的细节原理,可再回到此处开始看)

    1.1 gamma函数

        咱们先来考虑一个问题(此问题1包括下文的问题2-问题4皆取材自LDA数学八卦):

    1. 问题1 随机变量
    2. 把这n 个随机变量排序后得到顺序统计量
    3. 然后请问的分布是什么。

        为解决这个问题,可以尝试计算落在区间[x,x+Δx]的概率。即求下述式子的值:

        首先,把 [0,1] 区间分成三段 [0,x),[x,x+Δx],(x+Δx,1],然后考虑下简单的情形:即假设n 个数中只有1个落在了区间 [x,x+Δx]内,由于这个区间内的数X(k)是第k大的,所以[0,x)中应该有 k−1 个数,(x+Δx,1] 这个区间中应该有n−k 个数。如下图所示:

        从而问题转换为下述事件E:

        对于上述事件E,有:
        其中,o(Δx)表示Δx的高阶无穷小。显然,由于不同的排列组合,即n个数中有一个落在 [x,x+Δx]区间的有n种取法,余下n−1个数中有k−1个落在[0,x)的有 种组合,所以和事件E等价的事件一共有 个。
        如果有2个数落在区间[x,x+Δx]呢?如下图所示:
        类似于事件E,对于2个数落在区间[x,x+Δx]的事件E’:
        有:
       从上述的事件E、事件E‘中,可以看出,只要落在[x,x+Δx]内的数字超过一个,则对应的事件的概率就是 o(Δx)。于是乎有:
        从而得到 的概率密度函数 为:

        至此,本节开头提出的问题得到解决。然仔细观察的概率密度函数,发现式子的最终结果有阶乘,联想到阶乘在实数上的推广函数:

        两者结合是否会产生奇妙的效果呢?考虑到具有如下性质:

        故将代入到的概率密度函数中,可得:

        然后取,转换得到:

        如果熟悉beta分布的朋友,可能会惊呼:哇,竟然推出了beta分布!


    2 beta分布

    2.1 beta分布

        在概率论中,beta是指一组定义在 区间的连续概率分布,有两个参数 ,且
        beta分布的概率密度函数是:
        其中的 便是 函数:
        随机变量X服从参数为的beta分布通常写作:

    2.2 Beta-Binomial 共轭

        回顾下1.1节开头所提出的问题:“问题1 随机变量 ,把这n 个随机变量排序后得到顺序统计量 ,然后请问 的分布是什么。” 如果,咱们要在这个问题的基础上增加一些观测数据,变成 问题2
    • ,对应的顺序统计量是,需要猜测
    • , 中有个比p小,个比大;
    • 那么,请问的分布是什么。
        根据“Yi中有 个比 小, 个比 大”,换言之,Yi中有 个比 小, 个比 大,所以 中第 大的数。
        根据1.1节最终得到的结论“只要落在[x,x+Δx]内的数字超过一个,则对应的事件的概率就是 o(Δx)”,继而推出事件服从beta分布,从而可知 的概率密度函数为:
       
        熟悉贝叶斯方法(不熟悉的没事,参见 此文第一部分)的朋友心里估计又犯“嘀咕”了,这不就是贝叶斯式的思考过程么?
    1. 为了猜测,在获得一定的观测数据前,我们对的认知是:,此称为的先验分布;
    2. 然后为了获得这个结果“ 中有个比p小,个比大”,针对是做了次贝努利实验,所以服从二项分布
    3. 在给定了来自数据提供的的知识后,的后验分布变为
        回顾下 贝叶斯派思考问题的固定模式:
    • 先验分布 + 样本信息  后验分布
         上述思考模式意味着,新观察到的样本信息将修正人们以前对事物的认知。换言之,在得到新的样本信息之前,人们对 的认知是先验分布 ,在得到新的样本信息 后,人们对 的认知为
        类比到现在这个问题上,我们也可以试着写下:
        其中 对应的是二项分布 的计数。
        更一般的,对于非负实数 ,我们有如下关系

        针对于这种观测到的数据符合二项分布参数的先验分布和后验分布都是Beta分布的情况,就是Beta-Binomial共轭。换言之,Beta分布是二项式分布的共轭先验概率分布

        二项分布和Beta分布是共轭分布意味着,如果我们为二项分布的参数p选取的先验分布是Beta分布,那么以p为参数的二项分布用贝叶斯估计得到的后验分布仍然服从Beta分布。

        此外,如何理解参数 所表达的意义呢? 可以认为形状参数,通俗但不严格的理解是, 共同控制Beta分布的函数“长的样子”:形状千奇百怪,高低胖瘦,如下图所示:
      

    2.3 共轭先验分布

        什么又是共轭呢?轭的意思是束缚、控制,共轭从字面上理解,则是共同约束,或互相约束。
         在贝叶斯概率理论中,如果后验概率P(θ|x)和先验概率p(θ)满足同样的分布律,那么,先验分布和后验分布被叫做共轭分布,同时,先验分布叫做似然函数的共轭先验分布
        比如,某观测数据服从概率分布 P(θ)时,当观测到新的X数据时,我们一般会遇到如下问题:
    • 可否根据新观测数据X,更新参数θ?
    • 根据新观测数据可以在多大程度上改变参数θ,即
    • 当重新估计θ的时候,给出新参数值θ的新概率分布,即P(θ|x)
        事实上,根据根据贝叶斯公式可知:
        其中,P(x|θ)表示以预估θ为参数的x概率分布,可以直接求得,P(θ)是已有原始的θ概率分布。
        所以,如果我们选取P(x|θ)的共轭先验作为P(θ)的分布,那么P(x|θ)乘以P(θ),然后归一化的结果P(θ|x)跟和P(θ)的形式一样。换句话说,先验分布是P(θ),后验分布是P(θ|x), 先验分布跟后验分布同属于一个分布族,故称该分布族是θ的共轭先验分布(族)

        举个例子。投掷一个非均匀硬币,可以使用参数为θ的伯努利模型,θ为硬币为正面的概率,那么结果x的分布形式为:
        其共轭先验为beta分布,具有两个参数 ,称为超参数(hyperparameters)。且这两个参数决定了θ参数,其Beta分布形式为
        然后计算后验概率
        归一化这个等式后会得到另一个Beta分布,从而证明了Beta分布确实是伯努利分布的共轭先验分布。

    2.4 从beta分布推广到Dirichlet 分布

        接下来,咱们来考察beta分布的一个性质。
        如果 ,则有:
        注意到上式最后结果的右边积分
        其类似于概率分布 ,而对于这个分布有

        从而求得
        的结果为
        最后将此结果带入 的计算式,得到:

        最后的这个结果意味着对于Beta 分布的随机变量,其均值(期望)可以用来估计。此外,狄利克雷Dirichlet 分布也有类似的结论,即如果,同样可以证明有下述结论成立:

        那什么是Dirichlet 分布呢?简单的理解Dirichlet 分布就是一组连续多变量概率分布,是多变量普遍化的beta分布。为了纪念德国数学家约翰·彼得·古斯塔夫·勒热纳·狄利克雷(Peter Gustav Lejeune Dirichlet)而命名。狄利克雷分布常作为贝叶斯统计的先验概率。


    3 Dirichlet 分布

    3.1 Dirichlet 分布

        根据wikipedia上的介绍,维度K ≥ 2(x1,x2…xK-1维,共K个)的狄利克雷分布在参数α1, ..., αK > 0上、基于欧几里得空间RK-1里的勒贝格测度有个概率密度函数,定义为:

        其中,相当于是多项beta函数

        且

        此外,x1+x2+…+xK-1+xK=1,x1,x2…xK-1>0,且在(K-1)维的单纯形上,其他区域的概率密度为0。

        当然,也可以如下定义Dirichlet 分布

        其中的称为Dirichlet 分布的归一化系数:

        且根据Dirichlet分布的积分为1(概率的基本性质),可以得到:

    3.2 Dirichlet-Multinomial 共轭

        下面,在2.2节问题2的基础上继续深入,引出问题3

    • 排序后对应的顺序统计量,
    • 的联合分布是什么?
        为了简化计算,取x3满足x1+x2+x3=1,但只有x1,x2是变量,如下图所示:

        从而有:

        继而得到于是我们得到的联合分布为:

        观察上述式子的最终结果,可以看出上面这个分布其实就是3维形式的 Dirichlet 分布

        令,于是分布密度可以写为

        这个就是一般形式的3维 Dirichlet 分布,即便延拓到非负实数集合,以上概率分布也是良定义的。

        将Dirichlet分布的概率密度函数取对数,绘制对称Dirichlet分布的图像如下图所示(截取自wikipedia上):

        上图中,取K=3,也就是有两个独立参数x1,x2,分别对应图中的两个坐标轴,第三个参数始终满足x3=1-x1-x2且α1=α2=α3=α,图中反映的是参数α从α=(0.3, 0.3, 0.3)变化到(2.0, 2.0, 2.0)时的概率对数值的变化情况。

        为了论证Dirichlet分布是多项式分布的共轭先验概率分布,下面咱们继续在上述问题3的基础上再进一步,提出问题4

    1. 问题4  ,排序后对应的顺序统计量
    2. ,,(此处的p3非变量,只是为了表达方便),现在要猜测
    3. ,Yi中落到 三个区间的个数分别为 m1,m2,m3,m=m1+m2+m3;
    4.  问后验分布的分布是什么。

       为了方便讨论,记,及,根据已知条件“,Yi中落到 三个区间的个数分别为 m1,m2”,可得分别是这m+n个数中第大、第大的数。于是,后验分布应该为,即一般化的形式表示为:

        同样的,按照贝叶斯推理的逻辑,可将上述过程整理如下:

    1.  我们要猜测参数,其先验分布为
    2.  数据Yi落到三个区间 的个数分别为,所以服从多项分布
    3.  在给定了来自数据提供的知识后,的后验分布变为

        上述贝叶斯分析过程的直观表述为:

        令,可把从整数集合延拓到实数集合,从而得到更一般的表达式如下:

        针对于这种 观测到的数据符合多项分布,参数的先验分布和后验分布都是Dirichlet 分布的情况, 就是Dirichlet-Multinomial 共轭。换言之,至此已经证明了 Dirichlet 分布的确就是多项式分布的共轭先验概率分布。
         意味着,如果我们为多项分布的参数p选取的先验分布是Dirichlet分布,那么以p为参数的多项分布用贝叶斯估计得到的后验分布仍然服从Dirichlet分布。
        进一步,一般形式的Dirichlet 分布定义如下:
        而对于给定的 ,其多项分布为:
        结论是:Dirichlet分布 和多项分布 是共轭关系。


    4 主题模型LDA

            在开始下面的旅程之前,先来总结下我们目前所得到的最主要的几个收获:

    • 通过上文的第2.2节,我们知道beta分布是二项式分布的共轭先验概率分布:
      •  对于非负实数,我们有如下关系

        其中对应的是二项分布的计数。针对于这种观测到的数据符合二项分布,参数的先验分布和后验分布都是Beta分布的情况,就是Beta-Binomial 共轭。

    • 通过上文的3.2节,我们知道狄利克雷分布(Dirichlet分布)是多项式分布的共轭先验概率分布:
      •  从整数集合延拓到实数集合,从而得到更一般的表达式如下:

        针对于这种观测到的数据符合多项分布,参数的先验分布和后验分布都是Dirichlet 分布的情况,就是 Dirichlet-Multinomial 共轭。  ”
    • 以及贝叶斯派思考问题的固定模式:
      • 先验分布 + 样本信息  后验分布
           上述思考模式意味着,新观察到的样本信息将修正人们以前对事物的认知。换言之,在得到新的样本信息之前,人们对 的认知是先验分布 ,在得到新的样本信息 后,人们对 的认知为
    • 顺便提下频率派与贝叶斯派各自不同的思考方式:
      • 频率派把需要推断的参数θ看做是固定的未知常数,即概率虽然是未知的,但最起码是确定的一个值,同时,样本X 是随机的,所以频率派重点研究样本空间,大部分的概率计算都是针对样本X 的分布;
      • 贝叶斯派的观点则截然相反,他们认为待估计的参数是随机变量,服从一定的分布,而样本X 是固定的,由于样本是固定的,所以他们重点研究的是参数的分布。

        OK,在杀到终极boss——LDA模型之前,再循序渐进理解基础模型:Unigram model、mixture of unigrams model,以及跟LDA最为接近的pLSA模型。

       为了方便描述,首先定义一些变量:

    • 表示词,表示所有单词的个数(固定值)
    • 表示主题,是主题的个数(预先给定,固定值)
    • 表示语料库,其中的是语料库中的文档数(固定值)
    • 表示文档,其中的表示一个文档中的词数(随机变量)

    4.1 各个基础模型

    4.1.1 Unigram model

        对于文档,用表示词的先验概率,生成文档的概率为:

        其图模型为(图中被涂色的w表示可观测变量,N表示一篇文档中总共N个单词,M表示M篇文档):

        或为:

        unigram model假设文本中的词服从Multinomial分布,而我们已经知道Multinomial分布的先验分布为Dirichlet分布。
        上图中的表示在文本中观察到的第n个词,n∈[1,N]表示该文本中一共有N个单词。加上方框表示重复,即一共有N个这样的随机变量。其中,p和α是隐含未知变量:

    • p是词服从的Multinomial分布的参数
    • α是Dirichlet分布(即Multinomial分布的先验分布)的参数。

        一般α由经验事先给定,p由观察到的文本中出现的词学习得到,表示文本中出现每个词的概率。

    4.1.2 Mixture of unigrams model

        该模型的生成过程是:给某个文档先选择一个主题,再根据该主题生成文档,该文档中的所有词都来自一个主题。假设主题有,生成文档的概率为:
        其图模型为(图中被涂色的w表示可观测变量,未被涂色的z表示未知的隐变量,N表示一篇文档中总共N个单词,M表示M篇文档):

    4.2 PLSA模型

        啊哈,长征两万五,经过前面这么长的铺垫,终于快要接近LDA模型了!因为跟LDA模型最为接近的便是下面要阐述的这个pLSA模型,理解了pLSA模型后,到LDA模型也就一步之遥——给pLSA加上贝叶斯框架,便是LDA

    4.2.1 pLSA模型下生成文档

        OK,在上面的Mixture of unigrams model中,我们假定一篇文档只有一个主题生成,可实际中,一篇文章往往有多个主题,只是这多个主题各自在文档中出现的概率大小不一样。比如介绍一个国家的文档中,往往会分别从教育、经济、交通等多个主题进行介绍。那么在pLSA中,文档是怎样被生成的呢
        假设你要写M篇文档,由于一篇文档由各个不同的词组成,所以你需要确定每篇文档里每个位置上的词。
        再假定你一共有K个可选的主题,有V个可选的词,咱们来玩一个扔骰子的游戏。
    • 1. 假设你每写一篇文档会制作一颗K面的“文档-主题”骰子(扔此骰子能得到K个主题中的任意一个),和K个V面的“主题-词项” 骰子(每个骰子对应一个主题,K个骰子对应之前的K个主题,且骰子的每一面对应要选择的词项,V个面对应着V个可选的词)。
      • 比如可令K=3,即制作1个含有3个主题的“文档-主题”骰子,这3个主题可以是:教育、经济、交通。然后令V = 3,制作3个有着3面的“主题-词项”骰子,其中,教育主题骰子的3个面上的词可以是:大学、老师、课程,经济主题骰子的3个面上的词可以是:市场、企业、金融,交通主题骰子的3个面上的词可以是:高铁、汽车、飞机。
    • 2. 每写一个词,先扔该“文档-主题”骰子选择主题,得到主题的结果后,使用和主题结果对应的那颗“主题-词项”骰子,扔该骰子选择要写的词。
      • 先扔“文档-主题”的骰子,假设(以一定的概率)得到的主题是教育,所以下一步便是扔教育主题筛子,(以一定的概率)得到教育主题筛子对应的某个词:大学。
        • 上面这个投骰子产生词的过程简化下便是:“先以一定的概率选取主题,再以一定的概率选取词”。事实上,一开始可供选择的主题有3个:教育、经济、交通,那为何偏偏选取教育这个主题呢?其实是随机选取的,只是这个随机遵循一定的概率分布。比如可能选取教育主题的概率是0.5,选取经济主题的概率是0.3,选取交通主题的概率是0.2,那么这3个主题的概率分布便是{教育:0.5,经济:0.3,交通:0.2},我们把各个主题z在文档d中出现的概率分布称之为主题分布,且是一个多项分布。
        • 同样的,从主题分布中随机抽取出教育主题后,依然面对着3个词:大学、老师、课程,这3个词都可能被选中,但它们被选中的概率也是不一样的。比如大学这个词被选中的概率是0.5,老师这个词被选中的概率是0.3,课程被选中的概率是0.2,那么这3个词的概率分布便是{大学:0.5,老师:0.3,课程:0.2},我们把各个词语w在主题z下出现的概率分布称之为词分布,这个词分布也是一个多项分布。
        • 所以,选主题和选词都是两个随机的过程,先从主题分布{教育:0.5,经济:0.3,交通:0.2}中抽取出主题:教育,然后从该主题对应的词分布{大学:0.5,老师:0.3,课程:0.2}中抽取出词:大学
    • 3. 最后,你不停的重复扔“文档-主题”骰子和”主题-词项“骰子,重复N次(产生N个词),完成一篇文档,重复这产生一篇文档的方法M次,则完成M篇文档。
        上述 过程抽象出来即是PLSA的文档生成模型。 在这个过程中,我们并未关注词和词之间的出现顺序,所以pLSA是一种词袋方法。 具体说来,该模型假设一组共现(co-occurrence)词项关联着一个隐含的主题类别 。同时定义:
    • 表示海量文档中某篇文档被选中的概率。
    • 表示词在给定文档中出现的概率。
      • 怎么计算得到呢?针对海量文档,对所有文档进行分词后,得到一个词汇列表,这样每篇文档就是一个词语的集合。对于每个词语,用它在文档中出现的次数除以文档中词语总的数目便是它在文档中出现的概率
    • 表示具体某个主题在给定文档下出现的概率。
    • 表示具体某个词在给定主题下出现的概率,与主题关系越密切的词,其条件概率越大。
        利用上述的第1、3、4个概率,我们便可以按照如下的步骤得到“文档-词项”的生成模型:
    1. 按照概率选择一篇文档
    2. 选定文档后,从主题分布中按照概率选择一个隐含的主题类别
    3. 选定后,从词分布中按照概率选择一个词
        所以pLSA中生成文档的整个过程便是选定文档生成主题,确定主题生成词。

    4.2.1 根据文档反推其主题分布

        反过来,既然文档已经产生,那么如何根据已经产生好的文档反推其主题呢?这个利用看到的文档推断其隐藏的主题(分布)的过程(其实也就是产生文档的逆过程),便是主题建模的目的:自动地发现文档集中的主题(分布)。
        换言之,人类根据文档生成模型写成了各类文章,然后丢给了 计算机,相当于计算机看到的是一篇篇已经写好的文章。现在计算机需要根据一篇篇文章中看到的一系列词归纳出当篇文章的主题,进而得出各个主题各自不同的出现概率:主题分布。即文档d和单词w是可被观察到的,但主题z却是隐藏的。
        如下图所示( 图中被涂色的d、w表示可观测变量,未被涂色的z表示未知的隐变量,N表示一篇文档中总共N个单词,M表示M篇文档):
        上图中,文档d和词w是我们得到的样本(样本随机,参数虽未知但固定,所以pLSA属于频率派思想区别于下文要介绍的LDA中:样本固定,参数未知但不固定,是个随机变量,服从一定的分布,所以LDA属于贝叶斯派思想),可观测得到,所以 对于任意一篇文档,其是已知的。
        从而可以 根据 大量已知的文档-词项信息 ,训练出文档-主题 主题-词项 ,如下公式所示:
        故得到文档中每个词的生成概率为:

        由于可事先计算求出,未知,所以就是我们要估计的参数(值),通俗点说,就是要最大化这个θ

        用什么方法进行估计呢,常用的参数估计方法有极大似然估计MLE、最大后验证估计MAP、贝叶斯估计等等。因为该待估计的参数中含有隐变量z,所以我们可以考虑EM算法。

    4.2.1.1 EM算法的简单介绍

        EM算法,全称为Expectation-maximization algorithm,为期望最大算法,其基本思想是:首先随机选取一个值去初始化待估计的值,然后不断迭代寻找更优的使得其似然函数likelihood 比原来的要大。换言之,假定现在得到了,想求,使得

        EM的关键便是要找到的一个下界(注:其中,X表示已经观察到的随机变量),然后不断最大化这个下界,通过不断求解下界的极大化,从而逼近要求解的似然函数

        所以EM算法的一般步骤为:

    • 1. 随机选取或者根据先验知识初始化
    • 2. 不断迭代下述两步
      • ①给出当前的参数估计,计算似然函数的下界
      • ②重新估计参数θ,即求,使得
    • 3. 上述第二步后,如果收敛(即收敛)则退出算法,否则继续回到第二步。

        上述过程好比在二维平面上,有两条不相交的曲线,一条曲线在上(简称上曲线),一条曲线在下(简称下曲线),下曲线为上曲线的下界。现在对上曲线未知,只已知下曲线,为了求解上曲线的最高点,我们试着不断增大下曲线,使得下曲线不断逼近上曲线,下曲线在某一个点达到局部最大值并与上曲线在这点的值相等,记录下这个值,然后继续增大下曲线,寻找下曲线上与上曲线上相等的值,迭代到收敛(即收敛)停止,从而利用当前下曲线上的局部最大值当作上曲线的全局最大值(换言之,EM算法不保证一定能找到全局最优值)。如下图所示:

        以下是详细介绍。

        假定有训练集包含m个独立样本,希望从中找到该组数据的模型p(x,z)的参数。   

        然后通过极大似然估计建立目标函数--对数似然函数:

        这里,z是隐随机变量,直接找到参数的估计是很困难的。我们的策略是建立的下界,并且求该下界的最大值;重复这个过程,直到收敛到局部最大值。

        令Qi是z的某一个分布,Qi≥0,且结合Jensen不等式,有:

        为了寻找尽量紧的下界,我们可以让使上述等号成立,而若要让等号成立的条件则是:

        换言之,有以下式子成立:,且由于有:

        所以可得:

        最终得到EM算法的整体框架如下:

        OK,EM算法还会在本博客后面的博文中具体阐述。接下来,回到pLSA参数的估计问题上。

    4.2.1.2 EM算法估计pLSA的两未知参数

        首先尝试从矩阵的角度来描述待估计的两个未知变量

    • 假定用表示词表在主题上的一个多项分布,则可以表示成一个向量,每个元素表示词项出现在主题中的概率,即

    • 表示所有主题在文档上的一个多项分布,则可以表示成一个向量,每个元素表示主题出现在文档中的概率,即

        这样,巧妙的把转换成了两个矩阵。换言之,最终我们要求解的参数是这两个矩阵:

        由于词和词之间是相互独立的,所以整篇文档N个词的分布为:

        再由于文档和文档之间也是相互独立的,所以整个语料库中词的分布为(整个语料库M篇文档,每篇文档N个词):

        其中,表示词项在文档中的词频,表示文档di中词的总数,显然有
        从而得到整个语料库的词分布的对数似然函数(下述公式中有个小错误,正确的应该是:N为M,M为N):


        现在,我们需要最大化上述这个对数似然函数来求解参数。对于这种含有隐变量的最大似然估计,可以使用EM算法。EM算法,分为两个步骤:先E-step,后M-step。

    • E-step:假定参数已知,计算此时隐变量的后验概率。
        利用贝叶斯法则,可以得到:

    • M-step:带入隐变量的后验概率,最大化样本分布的对数似然函数,求解相应的参数。
        观察之前得到的对数似然函数的结果,由于文档长度可以单独计算,所以去掉它不影响最大化似然函数。此外,根据E-step的计算结果,把 代入,于是我们只要最大化下面这个函数  即可下述公式中有个小错误,正确的应该是:N为M,M为N

        这是一个多元函数求极值问题,并且已知有如下约束条件下述公式中有个小错误,正确的应该是:M为N

        熟悉凸优化的朋友应该知道,一般处理这种带有约束条件的极值问题,常用的方法便是拉格朗日乘数法,即通过引入拉格朗日乘子将约束条件和多元(目标)函数融合到一起,转化为无约束条件的极值问题。

        这里我们引入两个拉格朗日乘子,从而写出拉格朗日函数下述公式中有个小错误,正确的应该是:N为M,M为N

        因为我们要求解的参数是,所以分别对求偏导,然后令偏导结果等于0,得到下述公式中有个小错误,正确的应该是:N为M,M为N

        消去拉格朗日乘子,最终可估计出参数下述公式中有个小错误,正确的应该是:N为M,M为N

        综上,在pLSA中:

    1. 由于未知,所以我们用EM算法去估计这个参数的值。
    2. 而后,用表示词项出现在主题中的概率,即,用表示主题出现在文档中的概率,即,从而把转换成了“主题-词项”矩阵Φ(主题生成词),把转换成了“文档-主题”矩阵Θ(文档生成主题)。
    3. 最终求解出

    4.3 LDA模型

        事实上,理解了pLSA模型,也就差不多快理解了LDA模型,因为LDA就是在pLSA的基础上加层贝叶斯框架,即LDA就是pLSA的贝叶斯版本(正因为LDA被贝叶斯化了,所以才需要考虑历史先验知识,才加的两个先验参数)。

    4.3.1 pLSA跟LDA的对比:生成文档与参数估计

        在pLSA模型中,我们按照如下的步骤得到“文档-词项”的生成模型:

    1. 按照概率选择一篇文档
    2. 选定文档后,确定文章的主题分布
    3. 从主题分布中按照概率选择一个隐含的主题类别
    4. 选定后,确定主题下的词分布
    5. 从词分布中按照概率选择一个词 

        下面,咱们对比下本文开头所述的LDA模型中一篇文档生成的方式是怎样的:

    1. 按照先验概率选择一篇文档
    2. 从狄利克雷分布(即Dirichlet分布中取样生成文档 的主题分布,换言之,主题分布由超参数为的Dirichlet分布生成
    3. 从主题的多项式分布中取样生成文档第 j 个词的主题
    4. 从狄利克雷分布(即Dirichlet分布中取样生成主题对应的词语分布,换言之,词语分布由参数为的Dirichlet分布生成
    5. 从词语的多项式分布中采样最终生成词语 

        从上面两个过程可以看出,LDA在PLSA的基础上,为主题分布和词分布分别加了两个Dirichlet先验。

        继续拿之前讲解PLSA的例子进行具体说明。如前所述,在PLSA中,选主题和选词都是两个随机的过程,先从主题分布{教育:0.5,经济:0.3,交通:0.2}中抽取出主题:教育,然后从该主题对应的词分布{大学:0.5,老师:0.3,课程:0.2}中抽取出词:大学。

        而在LDA中, 选主题和选词依然都是两个随机的过程,依然可能是先从主题分布{教育:0.5,经济:0.3,交通:0.2}中抽取出主题:教育,然后再从该主题对应的词分布{大学:0.5,老师:0.3,课程:0.2}中抽取出词:大学
        那PLSA跟LDA的区别在于什么地方呢?区别就在于:
    • PLSA中,主题分布和词分布是唯一确定的,能明确的指出主题分布可能就是{教育:0.5,经济:0.3,交通:0.2},词分布可能就是{大学:0.5,老师:0.3,课程:0.2}
    • 但在LDA中,主题分布和词分布不再唯一确定不变,即无法确切给出。例如主题分布可能是{教育:0.5,经济:0.3,交通:0.2},也可能是{教育:0.6,经济:0.2,交通:0.2},到底是哪个我们不再确定(即不知道),因为它是随机的可变化的。但再怎么变化,也依然服从一定的分布,即主题分布跟词分布由Dirichlet先验随机确定
       看到这,你可能凌乱了,你说面对多个主题或词,各个主题或词被抽中的概率不一样,所以抽取主题或词是随机抽取,还好理解。但现在你说主题分布和词分布本身也都是不确定的,这是怎么回事?没办法,谁叫Blei等人“强行”给PLSA安了个贝叶斯框架呢,正因为LDA是PLSA的贝叶斯版本,所以主题分布跟词分布本身由先验知识随机给定。
        进一步,你会发现:
    • pLSA中,主题分布和词分布确定后,以一定的概率()分别选取具体的主题和词项,生成好文档。而后根据生成好的文档反推其主题分布、词分布时,最终用EM算法(极大似然估计思想)求解出了两个未知但固定的参数的值:(由转换而来)和(由转换而来)。
      • 文档d产生主题z的概率,主题z产生单词w的概率都是两个固定的值。
        • 举个文档d产生主题z的例子。给定一篇文档d,主题分布是一定的,比如{ P(zi|d), i = 1,2,3 }可能就是{0.4,0.5,0.1},表示z1、z2、z3,这3个主题被文档d选中的概率都是个固定的值:P(z1|d) = 0.4、P(z2|d) = 0.5、P(z3|d) = 0.1,如下图所示(图截取自沈博PPT上):

    • 但在贝叶斯框架下的LDA中,我们不再认为主题分布(各个主题在文档中出现的概率分布)和词分布(各个词语在某个主题下出现的概率分布)是唯一确定的(而是随机变量),而是有很多种可能。但一篇文档总得对应一个主题分布和一个词分布吧,怎么办呢?LDA为它们弄了两个Dirichlet先验参数,这个Dirichlet先验为某篇文档随机抽取出某个主题分布和词分布。
      • 文档d产生主题z(准确的说,其实是Dirichlet先验为文档d生成主题分布Θ,然后根据主题分布Θ产生主题z)的概率,主题z产生单词w的概率都不再是某两个确定的值,而是随机变量
        • 还是再次举下文档d具体产生主题z的例子。给定一篇文档d,现在有多个主题z1、z2、z3,它们的主题分布{ P(zi|d), i = 1,2,3 }可能是{0.4,0.5,0.1},也可能是{0.2,0.2,0.6},即这些主题被d选中的概率都不再认为是确定的值,可能是P(z1|d) = 0.4、P(z2|d) = 0.5、P(z3|d) = 0.1,也有可能是P(z1|d) = 0.2、P(z2|d) = 0.2、P(z3|d) = 0.6等等,而主题分布到底是哪个取值集合我们不确定(为什么?这就是贝叶斯派的核心思想,把未知参数当作是随机变量,不再认为是某一个确定的值),但其先验分布是dirichlet 分布,所以可以从无穷多个主题分布中按照dirichlet 先验随机抽取出某个主题分布出来。如下图所示(图截取自沈博PPT上):

        换言之,LDA在pLSA的基础上给这两参数 加了两个先验分布的参数( 贝叶斯化):一个主题分布的先验分布 Dirichlet分布 ,和一个词语分布的先验分布 Dirichlet分布
        综上,LDA真的只是pLSA的贝叶斯版本,文档生成后,两者都要根据文档去推断其主题分布和词语分布( 即两者本质都是为了估计给定文档生成主题,给定主题生成词语的概率),只是用的参数推断方法不同,在pLSA中用极大似然估计的思想去推断两未知的固定参数,而LDA则把这两参数弄成随机变量,且加入dirichlet先验。
        所以,pLSA跟LDA的本质区别就在于它们去估计未知参数所采用的思想不同,前者用的是频率派思想,后者用的是贝叶斯派思想。
        好比,我去一朋友家:
    • 按照频率派的思想,我估计他在家的概率是1/2,不在家的概率也是1/2,是个定值。
    • 按照贝叶斯派的思想,他在家不在家的概率不再认为是个定值1/2,而是随机变量。比如按照我们的经验(比如当天周末),猜测他在家的概率是0.6,但这个0.6不是说就是完全确定的,也有可能是0.7。如此,贝叶斯派没法确切给出参数的确定值(0.3,0.4,0.6,0.7,0.8,0.9都有可能),但至少明白在哪个范围或哪些取值(0.6,0.7,0.8,0.9)更有可能,哪个范围或哪些取值(0.3,0.4) 不太可能。进一步,贝叶斯估计中,参数的多个估计值服从一定的先验分布,而后根据实践获得的数据(例如周末不断跑他家),不断修正之前的参数估计,从先验分布慢慢过渡到后验分布。
        OK,相信已经解释清楚了。如果是在机器学习班上face-to-face,更好解释和沟通。

    4.3.2 LDA生成文档过程的进一步理解

        上面说,LDA中,主题分布  —— 比如{  P(zi), i =1,2,3 }等于{0.4,0.5,0.1}或{0.2,0.2,0.6} —— 是由dirichlet先验给定的,不是根据文档产生的。所以, LDA生成文档的过程中,先从dirichlet先验中“随机”抽取出主题分布,然后从主题分布中“随机”抽取出主题,最后从确定后的主题对应的词分布中“随机”抽取出词。
        那么,dirichlet先验到底是如何“随机”抽取主题分布的呢?
        事实上,从dirichlet分布中随机抽取主题分布,这个过程不是完全随机的。为了说清楚这个问题,咱们得回顾下dirichlet分布。事实上,如果我们取3个事件的话,可以建立一个三维坐标系,类似xyz三维坐标系,这里,我们把3个坐标轴弄为p1、p2、p3,如下图所示:

        在这个三维坐标轴所划分的空间里,每一个坐标点(p1,p2,p3)就对应着一个主题分布,且某一个点(p1,p2,p3)的大小表示3个主题z1、z2、z3出现的概率大小(因为各个主题出现的概率和为1,所以p1+p2+p3 = 1,且p1、p2、p3这3个点最大取值为1)。比如(p1,p2,p3) = (0.4,0.5,0.1)便对应着主题分布{ P(zi), i =1,2,3 } = {0.4,0.5,0.1}。

        可以想象到,空间里有很多这样的点(p1,p2,p3),意味着有很多的主题分布可供选择,那dirichlet分布如何选择主题分布呢?把上面的斜三角形放倒,映射到底面的平面上,便得到如下所示的一些彩图(3个彩图中,每一个点对应一个主题分布,高度代表某个主题分布被dirichlet分布选中的概率,且选不同的,dirichlet 分布会偏向不同的主题分布):

        我们来看上图中左边这个图,高度就是代表dirichlet分布选取某个坐标点(p1,p2,p3)(这个点就是一个主题分布)的概率大小。如下图所示,平面投影三角形上的三个顶点上的点:A=(0.9,0.05,0.05)、B=(0.05,0.9,0.05)、C=(0.05,0.05,0.9)各自对应的主题分布被dirichlet分布选中的概率值很大,而平面三角形内部的两个点:D、E对应的主题分布被dirichlet分布选中的概率值很小。

        所以虽然说dirichlet分布是随机选取任意一个主题分布的,但依然存在着P(A) = P(B) = P(C) >> P(D) = P(E),即dirichlet分布还是“偏爱”某些主题分布的。至于dirichlet分布的参数 是如何决定dirichlet分布的形状的,可以从dirichlet分布的定义和公式思考。
        此外,就算说“随机”选主题也是根据主题分布来“随机”选取,这里的随机不是完全随机的意思,而是根据各个主题出现的概率值大小来抽取。比如当dirichlet先验为文档d生成的主题分布{ P(zi), i =1,2,3 }是{0.4,0.5,0.1}时,那么主题z2在文档d中出现的概率便是0.5。所以,从主题分布中抽取主题,这个过程也不是完全随机的,而是按照各个主题出现的概率值大小进行抽取。

    4.3.3 pLSA跟LDA的概率图对比

        接下来,对比下LDA跟pLSA的概率模型图模型,左图是pLSA,右图是LDA(右图不太规范,z跟w都得是小写, 其中,阴影圆圈表示可观测的变量,非阴影圆圈表示隐变量,箭头表示两变量间的条件依赖性conditional dependency,方框表示重复抽样,方框右下角的数字代表重复抽样的次数):
                 
        对应到上面右图的LDA,只有W / w是观察到的变量,其他都是隐变量或者参数,其中,Φ表示词分布,Θ表示主题分布,  是主题分布Θ的先验分布(即Dirichlet 分布)的参数, 是词分布Φ的先验分布(即Dirichlet 分布)的参数,N表示文档的单词总数,M表示文档的总数。
        所以,对于一篇文档d中的每一个单词,LDA根据先验知识 确定某篇文档的主题分布θ,然后从该文档所对应的多项分布(主题分布)θ中抽取一个主题z,接着根据先验知识 确定当前主题的词语分布ϕ,然后从主题z所对应的多项分布(词分布)ϕ中抽取一个单词w。然后将这个过程重复N次,就产生了文档d。
        换言之:
    1. 假定语料库中共有M篇文章,每篇文章下的Topic的主题分布是一个从参数为的Dirichlet先验分布中采样得到的Multinomial分布,每个Topic下的词分布是一个从参数为的Dirichlet先验分布中采样得到的Multinomial分布。
    2. 对于某篇文章中的第n个词,首先从该文章中出现的每个主题的Multinomial分布(主题分布)中选择或采样一个主题,然后再在这个主题对应的词的Multinomial分布(词分布)中选择或采样一个词。不断重复这个随机生成过程,直到M篇文章全部生成完成。
        综上,M 篇文档会对应于 M 个独立的 Dirichlet-Multinomial 共轭结构,K 个 topic 会对应于 K 个独立的 Dirichlet-Multinomial 共轭结构。
    • 其中,→θ→z 表示生成文档中的所有词对应的主题,显然 →θ 对应的是Dirichlet 分布,θ→z 对应的是 Multinomial 分布,所以整体是一个 Dirichlet-Multinomial 共轭结构,如下图所示:
    • 类似的,→φ→w,容易看出, 此时β→φ对应的是 Dirichlet 分布, φ→w 对应的是 Multinomial 分布, 所以整体也是一个Dirichlet-Multinomial 共轭结构,如下图所示:

    4.3.4 pLSA跟LDA参数估计方法的对比

        上面对比了pLSA跟LDA生成文档的不同过程,下面,咱们反过来,假定文档已经产生,反推其主题分布。那么,它们估计未知参数所采用的方法又有什么不同呢?
    • 在pLSA中,我们使用EM算法去估计“主题-词项”矩阵Φ(由转换得到)和“文档-主题”矩阵Θ(由转换得到)这两个参数,而且这两参数都是个固定的值,只是未知,使用的思想其实就是极大似然估计MLE。
    • 而在LDA中,估计Φ、Θ这两未知参数可以用变分(Variational inference)-EM算法,也可以用gibbs采样,前者的思想是最大后验估计MAPMAP与MLE类似,都把未知参数当作固定的值,后者的思想是贝叶斯估计。贝叶斯估计是对MAP的扩展,但它与MAP有着本质的不同,即贝叶斯估计把待估计的参数看作是服从某种先验分布的随机变量。
      • 关于贝叶斯估计再举个例子。假设中国的大学只有两种:理工科和文科,这两种学校数量的比例是1:1,其中,理工科男女比例7:1,文科男女比例1:7。某天你被外星人随机扔到一个校园,问你该学校可能的男女比例是多少?然后,你实际到该校园里逛了一圈,看到的5个人全是男的,这时候再次问你这个校园的男女比例是多少?
    1. 因为刚开始时,有先验知识,所以该学校的男女比例要么是7:1,要么是1:7,即P(比例为7:1) = 1/2,P(比例为1:7) = 1/2。
    2. 然后看到5个男生后重新估计男女比例,其实就是求P(比例7:1|5个男生)= ?,P(比例1:7|5个男生) = ?
    3. 用贝叶斯公式,可得:P(比例7:1|5个男生) = P(比例7:1)*P(5个男生|比例7:1) / P(5个男生),P(5个男生)是5个男生的先验概率,与学校无关,所以是个常数;类似的,P(比例1:7|5个男生) = P((比例1:7)*P(5个男生|比例1:7)/P(5个男生)。
    4. 最后将上述两个等式比一下,可得:P(比例7:1|5个男生)/P(比例1:7|5个男生) = {P((比例7:1)*P(5个男生|比例7:1)} / { P(比例1:7)*P(5个男生|比例1:7)}。
        由于LDA把要估计的主题分布和词分布看作是其先验分布是Dirichlet分布的随机变量,所以, 在LDA这个估计主题分布、词分布的过程中,它们的先验分布(即Dirichlet分布)事先由人为给定,那么LDA就是要去求它们的后验分布(LDA中可用gibbs采样去求解它们的后验分布,得到期望)!
       此外,不厌其烦的再插一句,在LDA中,主题分布和词分布本身都是多项分布,而由上文3.2节可知“Dirichlet分布是多项式分布的共轭先验概率分布”,因此选择Dirichlet 分布作为它们的共轭先验分布。意味着为多项分布的参数p选取的先验分布是Dirichlet分布,那么以p为参数的多项分布用贝叶斯估计得到的后验分布仍然是Dirichlet分布。

    4.3.5 LDA参数估计:Gibbs采样

        理清了LDA中的物理过程,下面咱们来看下如何学习估计。

        类似于pLSA,LDA的原始论文中是用的变分-EM算法估计未知参数,后来发现另一种估计LDA未知参数的方法更好,这种方法就是:Gibbs Sampling,有时叫Gibbs采样或Gibbs抽样,都一个意思。Gibbs抽样是马尔可夫链蒙特卡尔理论(MCMC)中用来获取一系列近似等于指定多维概率分布(比如2个或者多个随机变量的联合概率分布)观察样本的算法。

        OK,给定一个文档集合,w是可以观察到的已知变量,是根据经验给定的先验参数,其他的变量z,θ和φ都是未知的隐含变量,需要根据观察到的变量来学习估计的。根据LDA的图模型,可以写出所有变量的联合分布:


        注:上述公式中及下文中,等价上文中定义的等价于上文中定义的等价于上文中定义的,等价于上文中定义的

        因为产生主题分布θ,主题分布θ确定具体主题,且产生词分布φ、词分布φ确定具体词,所以上述式子等价于下述式子所表达的联合概率分布

        其中,第一项因子表示的是根据确定的主题和词分布的先验分布参数采样词的过程,第二项因子是根据主题分布的先验分布参数采样主题的过程,这两项因子是需要计算的两个未知参数

        由于这两个过程是独立的,所以下面可以分别处理,各个击破。

        第一个因子,可以根据确定的主题和从先验分布取样得到的词分布Φ产生:

        由于样本中的词服从参数为主题的独立多项分布,这意味着可以把上面对词的乘积分解成分别对主题和对词的两层乘积:

        其中,是词 t 在主题 k 中出现的次数。

        回到第一个因子上来。目标分布需要对词分布Φ积分,且结合我们之前在3.1节定义的Dirichlet 分布的归一化系数的公式

        可得:

        这个结果可以看作K个Dirichlet-Multinomial模型的乘积。
        现在开始求第二个因子。类似于的步骤,先写出条件分布,然后分解成两部分的乘积:

        其中, 表示的单词 i 所属的文档,是主题 k 在文章 m 中出现的次数。

        对主题分布Θ积分可得:

        综合第一个因子和第二个因子的结果,得到的联合分布结果为

        接下来, 有了联合分布,咱们便可以通过联合分布来计算在给定可观测变量 w 下的隐变量 z 的条件分布(后验分布)来进行贝叶斯分析
        换言之,有了这个联合分布后,要求解第m篇文档中的第n个词(下标为 的词)的全部条件概率就好求了。
        先定义几个变量。 表示除去 的词,
        然后,排除当前词的主题分配,即根据其他词的主题分配和观察到的单词来计算当前词主题的概率公式为:
         勘误:考虑到 ,所以上述公式的第二行的分子,非p(w,z) *p(z),而是p(w|z)*p(z)。
        且有:

        最后一步,便是根据Markov链的状态 获取主题分布的参数Θ和词分布的参数Φ。
        换言之根据贝叶斯法则和Dirichlet先验,以及上文中得到的 各自被分解成两部分乘积的结果,可以计算得到 每个文档上Topic的后验分布和每个Topic下的词的后验分布分别如下(据上文可知: 其后验分布跟它们的先验分布一样,也都是 Dirichlet 分布
        其中, 是构成文档m的主题数向量, 是构成主题k的词项数向量。

        此外,别忘了上文中2.4节所述的Dirichlet的一个性质,如下:

         “ 如果,同样可以证明有下述结论成立:

        即:如果 ,则 中的任一元素 的期望是:
        可以看出,超参数 的直观意义就是事件先验的伪计数(prior pseudo-count)。 
        所以, 最终求解的Dirichlet 分布期望为
        然后将 的结果代入之前得到的 的结果中,可得:
        仔细观察上述结果,可以发现,式子的右半部分便是 ,这个概率的值对应着 的路径概率。如此,K 个topic 对应着K条路径,Gibbs Sampling 便在这K 条路径中进行采样,如下图所示:
        何等奇妙,就这样,Gibbs Sampling通过求解出主题分布和词分布的后验分布,从而成功解决主题分布和词分布这两参数未知的问题。


    5 读者微评


        本文发表后,部分热心的读者在微博上分享了他们自己理解LDA的心得,也欢迎更多朋友分享你的理解心得(比如评论在本文下,或评论在 微博上),从而在分享、讨论的过程中让更多人可以更好的理解:
    1. @SiNZeRo:lda 如果用em就是 map估计了. lda本意是要去找后验分布 然后拿后验分布做bayesian分析. 比如theta的期望 . 而不是把先验作为正则化引入。最后一点gibbs sampling其实不是求解的过程 是去explore后验分布 去采样 用于求期望.
    2. @研究者July:好问题好建议,这几天我陆续完善下!//@帅广应s:LDA这个东西该怎么用?可以用在哪些地方?还有就是Gibbs抽样的原理是什么?代码怎么实现?如果用EM来做,代码怎么实现? LDA模型的变形和优化有哪些?LDA不适用于解决哪类的问题?总之,不明白怎么用,参数怎么调优? 
    3. @xiangnanhe:写的很好,4.1.3节中的那两个图很赞,非常直观的理解了LDA模型加了先验之后在学参数的时候要比PLSI更灵活;PLSI在学参数的过程中比较容易陷入local minimum然后overfitting。
    4. @asker2:无论是pLSA中,还是LDA中,主题分布和词分布本身是固定的存在,但都未知。pLSA跟LDA的区别在于,去探索这两个未知参数的方法或思想不一样。pLSA是求到一个能拟合文本最好的参数(分布),这个值就认为是真实的参数。但LDA认为,其实我们没法去完全求解出主题分布、词分布到底是什么参数,我们只能把它们当成随机变量,通过缩小其方差(变化度)来尽量让这个随机变量变得更“确切”。换言之,我们不再求主题分布、词分布的具体值,而是通过这些分布生成的观测值(即实际文本)来反推分布的参数的范围,即在什么范围比较可能,在什么范围不太可能。所以,其实这就是一种贝叶斯分析的思想,虽然无法给出真实值具体是多少,但可以按照经验给一个相对合理的真实值服从的先验分布,然后从先验出发求解其后验分布。
    5. ..


    6 参考文献与推荐阅读

    1. Blei, David M.; Ng, Andrew Y.; Jordan, Michael I. Latent Dirichlet allocation(LDA原始论文):http://www.jmlr.org/papers/volume3/blei03a/blei03a.pdf
    2. Blei. Probabilistic Topic Models:http://www.cs.princeton.edu/~blei/papers/Blei2012.pdf,一网友的翻译:http://www.cnblogs.com/siegfang/archive/2013/01/30/2882391.html
    3. 一堆wikipedia,比如隐含狄利克雷分布LDA的wiki:http://zh.wikipedia.org/wiki/%E9%9A%90%E5%90%AB%E7%8B%84%E5%88%A9%E5%85%8B%E9%9B%B7%E5%88%86%E5%B8%83,狄利克雷分布的wiki:http://zh.wikipedia.org/wiki/%E7%8B%84%E5%88%A9%E5%85%8B%E9%9B%B7%E5%88%86%E5%B8%83
    4. 从贝叶斯方法谈到贝叶斯网络 ;
    5. rickjin的LDA数学八卦(力荐,本文部分图片和公式来自于此文档)网页版:http://www.flickering.cn/tag/lda/,PDF版:http://emma.memect.com/t/9756da9a47744de993d8df13a26e04e38286c9bc1c5a0d2b259c4564c6613298/LDA
    6. Thomas Hofmann.Probabilistic Latent Semantic Indexing(pLSA原始论文):http://cs.brown.edu/~th/papers/Hofmann-SIGIR99.pdf
    7. Gregor Heinrich.Parameter estimation for text analysis(关于Gibbs 采样最精准细致的论述):http://www.arbylon.net/publications/text-est.pdf
    8. Probabilistic latent semantic analysis (pLSA):http://blog.tomtung.com/2011/10/plsa/http://blog.tomtung.com/2011/10/plsa/
    9. 《概率论与数理统计教程第二版 茆诗松等人著》,如果忘了相关统计分布,建议复习此书或此文第二部分;
    10. 支持向量机通俗导论:理解SVM的三层境界》,第二部分关于拉格朗日函数的讨论;
    11. 机器学习班第11次课上,邹博讲EM & GMM的PPT:http://pan.baidu.com/s/1i3zgmzF
    12. 机器学习班第12次课上,邹博讲主题模型LDA的PPT:http://pan.baidu.com/s/1jGghtQm
    13. 主题模型之pLSA:http://blog.jqian.net/post/plsa.html
    14. 主题模型之LDA:http://blog.jqian.net/post/lda.html
    15. 搜索背后的奥秘——浅谈语义主题计算:http://www.semgle.com/search-engine-algorithms-mystery-behind-search-on-the-calculation-of-semantic-topic
    16. LDA的EM推导:http://www.cnblogs.com/hebin/archive/2013/04/25/3043575.html
    17. Machine Learning读书会第8期上,沈博讲主题模型的PPT:http://vdisk.weibo.com/s/zrFL6OXKgKMAf
    18. Latent Dirichlet Allocation (LDA)- David M.Blei:http://www.xperseverance.net/blogs/2012/03/17/
    19. 用GibbsLDA做Topic Modeling:http://weblab.com.cityu.edu.hk/blog/luheng/2011/06/24/%E7%94%A8gibbslda%E5%81%9Atopic-modeling/#comment-87
    20. 主题模型在文本挖掘中的应用:http://net.pku.edu.cn/~zhaoxin/Topic-model-xin-zhao-wayne.pdf
    21. 二项分布和多项分布,beta分布的对比:http://www.cnblogs.com/wybang/p/3206719.html
    22. LDA简介:http://cos.name/2010/10/lda_topic_model/
    23. LDA的相关论文、工具库:http://site.douban.com/204776/widget/notes/12599608/note/287085506/
    24. 一个网友学习LDA的心得:http://www.xuwenhao.com/2011/03/20/suggestions-for-programmers-to-learn-lda/
    25. http://blog.csdn.net/hxxiaopei/article/details/7617838
    26. 主题模型LDA及其在微博推荐&广告算法中的应用:http://www.wbrecom.com/?p=136
    27. LDA发明人之一Blei 写的毕业论文:http://www.cs.princeton.edu/~blei/papers/Blei2004.pdf
    28. LDA的一个C实现:http://www.cs.princeton.edu/~blei/lda-c/index.html
    29. LDA的一些其它资料:http://www.xperseverance.net/blogs/2012/03/657/


    展开全文
  • LDA模型介绍

    千次阅读 2019-11-13 10:13:04
    LDA模型 LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题 和文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是通过“文章以一定概率选择...
  • 基于增强的LDA模型微博热点话题发现,徐慧,夏楠楠,微博已经成为数亿计的用户发布大量信息,从这些庞大的数据信息中提取热点话题成为挑战之一。基于LDA模型对于微博热点话题的挖掘具
  • 用Python实现L-LDA模型(标签潜在Dirichlet分配模型) 参考: 标记的LDA:多标签语料库中信用归因的受监管主题模型Daniel Ramage ... 文本分析的参数估计,Gregor Heinrich。 潜在的Dirichlet分配,David M. ...
  • 在传统模糊C-均值聚类算法的基础上,提出了一种新型区间值数据模糊聚类算法。...提出了区间值数据模糊聚类的数学模型,并拓广模糊C-均值算法对区间值数据进行聚类。仿真验证了所提出算法的有效性。
  • LDA模型详解

    万次阅读 2018-08-14 14:26:06
    LDA是自然语言处理中非常常用的一个主题模型,全称是隐含狄利克雷分布(Latent Dirichlet Allocation),简称LDA。作用是将文档集中每篇文档的主题以概率分布的形式给出,然后通过分析分到同一主题下的文档抽取其...
  • 文章目录训练LDA模型困惑度计算得到一段文本的主题全部代码及案例(可直接运行) 首先使用gensim库: pip install gensim 训练LDA模型 import gensim # pip install gensim from gensim import corpora def train_...
  • LDA是一种文档主题生成模型,也称为三层贝叶斯概率模型,包含词、主题和文档三层结构。利用文档中单词的共现关系来对单词按主题聚类,得到“文档-主题”和“主题-单词”2个概率分布。 •LDA认为一篇文章的每个词...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,622
精华内容 9,448
关键字:

lda模型

友情链接: apsj.rar