【python笔记】tomotopy | 速度最快的LDA主题模型

【python笔记】tomotopy | 速度最快的LDA主题模型【python笔记】tomotopy|速度最快的LDA主题模型_tomotopy-0.12.7

写论文见到的一篇文章
感觉很有用处
原文链接
这个链接不知道是不是他自己的原文链接,我在他下边的博客地址里翻了半天也没找到,但是博客的名字是一样的(应该是一样的叭,如果大家又看到原文,麻烦把正确的链接贴在评论区,我来修改一下嘻嘻,感谢)

刚刚发现他有博客欸,整理的很不错哇,适合我这种菜鸡(啊哈哈哈)
这里附上他的博客地址
详细代码可以去GitHub看他的博客内容

下面是我的粗糙的学习笔记整理概括


1.tomotopy简介

在这里插入图片描述tomotopy 是 tomoto(主题建模工具)的 Python 扩展,它是用 C++ 编写的基于 Gibbs 采样的主题模型库。支持的主题模型包括 LDA、DMR、HDP、MG-LDA、PA 和 HPA, 利用现代 CPU 的矢量化来最大化速度。
实例代码

下图中同样的数据集, tomotopy迭代200次,gensim迭代10次的情况下, tomotopy与gensim耗时对比图,由此可见tomotopy训练主题模型速度之快。
在这里插入图片描述当前版本的 tomotopy 支持的主题模型包括

潜在狄利克雷分配(LDAModel)
标记的 LDA(LLDA 模型)
部分标记的 LDA(PLDA 模型)
监督LDA(SLDA模型)
Dirichlet 多项回归 (DMRModel)
广义狄利克雷多项回归 (GDMRModel)
分层狄利克雷过程 (HDPModel)
分层LDA(HLDA模型)
多粒 LDA(MGLDA 模型)
弹珠盘分配(PAModel)
分层 PA (HPAModel)
相关主题模型(CTModel)
动态主题模型 (DTModel)
基于伪文档的主题模型(PTModel)。

2.安装


!pip3 install tomotopy==0.12.2
!pip3 install pyLDAvis==3.3.1  

#目前,tomotopy 可以利用 AVX2、AVX 或 SSE2 SIMD 指令集来最大程度利用PC的
import tomotopy as tp

tp.isa
#将会输出'avx2'

如果 tp.isa 返回 None,则训练过程可能需要很长时间。

3.数据的导入

import pandas as pd

df = pd.read_csv('disaster_news.csv')
df.head()

在这里插入图片描述

4.数据预处理

import re
import jieba
from cntext import STOPWORDS_zh


def segment(text):
    words = jieba.lcut(text)
    words = [w for w in words if w not in STOPWORDS_zh]
    return words

#####test可以设置为读取一个文件什么的,按自己需要的情况修改
test = "云南永善县级地震已致人伤间民房受损中新网月日电据云南昭通市防震减灾局官方网站消息截至日时云南昭通永善县级地震已造成人受伤其中重伤人轻伤人已全部送医院救治民房受损户间倒塌户间个乡镇所学校不同程度受损目前被损毁电力交通通讯设施已全部抢通修复当地已调拨帐篷顶紧急转移万人月日时分云南昭通永善县发生里氏级地震震源深度公里当地震感强烈此外成都等四川多地也有明显震感"
print(segment(test))

#####这句应该是说写成一个列表,就是第一列是原本的text内容后边追加的第二列是做好预处理的文本
df['words'] = df['text'].apply(segment)
df.head()
####贴了原文的图,对比一下上下的图片

在这里插入图片描述

5.找最佳主题数

正常的步骤应该认真对待这步,在一定区间范围内,根据模型得分找到合理的K。这里使用tomotopy提供的主题一致性coherence得分假装找一下。

我们期望的图应该的topic coherence随着 number of topics增加而增加,然后到某个topic值趋于平稳。

tomotopy每次运行得到的图形状不一样,为了保证运行结果具有可比性,设置了随机种子seed为555,你也可以根据需要改为自己需要的随机状态(这里有点像炼丹)。经过运行发现k=5比较合适。

def find_k(docs, min_k=1, max_k=20, min_df=2):
    #min_df 词语最少出现在2个文档中
    import matplotlib.pyplot as plt
    scores = []
    for k in range(min_k, max_k):
        #seed随机种子,保证在大邓这里运行结果与你运行的结果一样
        mdl = tp.LDAModel(min_df=min_df, k=k, seed=555)
        for words in docs:
            if words:
                mdl.add_doc(words)
        mdl.train(20)
        coh = tp.coherence.Coherence(mdl)
        scores.append(coh.get_score())

    #x = list(range(min_k, max_k - 1)) # 区间最右侧的值。注意:不能大于max_k
    #print(x)
    #print()
    plt.plot(range(min_k, max_k), scores)
    plt.xlabel("number of topics")
    plt.ylabel("coherence")
    plt.show()
    
    
find_k(docs=df['words'], min_k=1, max_k=10, min_df=2)

在这里插入图片描述

也可以计算困惑度perplexity,困惑度越小越好(参考链接但我看评论区也有说这个计算方法不对的,大家仅供参考哈,我没用上这个困惑度,CSDN也有很多资源,大家自己找找喔)

6. 训练lda

使用tomotopy的LDA模型, 话题数K=5

import tomotopy as tp

#初始化LDA
mdl = tp.LDAModel(k=5, min_df=2, seed=555)
for words in df['words']:
    #确认words 是 非空词语列表
    if words:
        mdl.add_doc(words=words)

#训练
mdl.train()

#查看每个topic feature words
for k in range(mdl.k):
    print('Top 10 words of topic #{}'.format(k))
    print(mdl.get_topic_words(k, top_n=10))
    print('\n')
输出内容(我是原文贴过来的,格式会怪怪的)
Top 10 words of topic #0
[('一辆', 0.02751251682639122), ('事故', 0.021704642102122307), ('记者', 0.018342
189490795135), ('死亡', 0.01650812290608883), ('造成', 0.014062701724469662), ('人
员', 0.013909862376749516), ('现场', 0.013451346196234226), ('受伤', 0.0126871513
20278645), ('相撞', 0.011922957375645638), ('货车', 0.011922957375645638)]


   Top 10 words of topic #1 [('学生', 0.02709135226905346), ('食物中毒', 0.02498047426342964), ('出现', 0.019175563007593155), ('医院', 0.016185153275728226), ('事件', 0.013546556234359741), ('调查', 0.013194743543863297), ('年月日', 0.012842929922044277), ('治疗', 0.012667023576796055), ('症状', 0.011787491850554943), ('名', 0.011259771883487701)]

   Top 10 words of topic #2 [('现场', 0.018848909065127373), ('发生', 0.01677251048386097), ('医院', 0.015015557408332825), ('起火', 0.014216942712664604), ('原因', 0.012140544131398201), ('目前', 0.012140544131398201), ('救治', 0.01150165218859911), ('进行', 0.011022482998669147), ('名', 0.009425252676010132), ('火势', 0.009265529923141003)]

   Top 10 words of topic #3 [('发生', 0.03348556533455849), ('爆炸', 0.022389251738786697), ('造成', 0.019663840532302856), ('死亡', 0.01713310182094574), ('受伤', 0.016938429325819016), ('年月日', 0.016354413703083992), ('轿车', 0.012655640952289104), ('警方', 0.012460969388484955), ('袭击', 0.012266295962035656), ('事件', 0.011487606912851334)]

   Top 10 words of topic #4 [('地震', 0.047826822847127914), ('发生', 0.03555167838931084), ('火灾', 0.03140682727098465), ('时分', 0.020885275676846504), ('级', 0.015783920884132385), ('时间', 0.013870910741388798), ('公里', 0.013711493462324142), ('人员伤亡', 0.013073823414742947), ('记者', 0.013073823414742947), ('震感', 0.012276736088097095)]

7.可视化

可以做一个看着很高级的图啊哈哈哈哈

import pyLDAvis
import numpy as np
import warnings
warnings.filterwarnings('ignore', category=Warning)

#在notebook显示
pyLDAvis.enable_notebook()

#获取pyldavis需要的参数
topic_term_dists = np.stack([mdl.get_topic_word_dist(k) for k in range(mdl.k)])
doc_topic_dists = np.stack([doc.get_topic_dist() for doc in mdl.docs])
doc_topic_dists /= doc_topic_dists.sum(axis=1, keepdims=True)
doc_lengths = np.array([len(doc.words) for doc in mdl.docs])
vocab = list(mdl.used_vocabs)
term_frequency = mdl.used_vocab_freq


prepared_data = pyLDAvis.prepare(
    topic_term_dists, 
    doc_topic_dists, 
    doc_lengths, 
    vocab, 
    term_frequency,
    start_index=0, # tomotopy话题id从0开始,pyLDAvis话题id从1开始
    sort_topics=False #注意:否则pyLDAvis与tomotopy内的话题无法一一对应。 
)


#可视化结果存到html文件中
#pyLDAvis.save_html(prepared_data, 'ldavis.html')

#notebook中显示
pyLDAvis.display(prepared_data)

在这里插入图片描述

8.某文档主题预测

import jieba
from cntext import STOPWORDS_zh

#预测
doc = '云南永善县级地震已致伤间民房受损中新网日电云南昭通市防震减灾局官方网站消息日时云南昭通永善县级地震造成受伤重伤轻伤送医院救治民房受损户间倒塌户间乡镇学校不同程度受损目前损毁电力交通通讯设施抢通修复调拨帐篷顶紧急转移万人时分云南昭通永善县发生里氏级地震震源深度公里震感强烈成都四川多地明显震感'
words = [w for w in jieba.lcut(doc) if w not in STOPWORDS_zh]

#构造tomotopy需要的数据
doc_inst = mdl.make_doc(words=words)
topic_dist, ll = mdl.infer(doc_inst)
print("Topic Distribution for Unseen Docs: ", topic_dist)
输出内容
Topic Distribution for Unseen Docs:  [0.11645161 0.10240361 0.5342029  0.03622254 0.21071935]

列表长度为5, 列表第三个数值(topic #2)数值最大,该文本最大的可能性是topic #2

9.指定主题特征词

如果对数据比较了解,已经知道有一些主题,可以把比较明显的词语分配给指定的topic_id。

mdl = tp.LDAModel(k=5, min_df=2, seed=555)

for words in df['words']:
    if words:
        mdl.add_doc(words)

#把word相撞 分配给topic_0, 权重设置为1, 其他topic权重设置为0.1
#注意这里的range(5) 5是对应的k值
mdl.set_word_prior('相撞', [1.0 if k == 0 else 0.1 for k in range(5)])
#把word地震 分配给topic_1, 权重设置为1, 其他topic权重设置为0.1
mdl.set_word_prior('地震', [1.0 if k == 1 else 0.1 for k in range(5)])
#把word火灾 分配给topic_2, 权重设置为1, 其他topic权重设置为0.1
mdl.set_word_prior('火灾', [1.0 if k == 2 else 0.1 for k in range(5)])
#把word中毒 分配给topic_3, 权重设置为1, 其他topic权重设置为0.1
mdl.set_word_prior('中毒', [1.0 if k == 3 else 0.1 for k in range(5)])
#把word袭击 分配给topic_4, 权重设置为1, 其他topic权重设置为0.1
mdl.set_word_prior('袭击', [1.0 if k == 4 else 0.1 for k in range(5)])

mdl.train()
mdl.summary() 

输出内容


个人小结

本文仅作学习笔记留存(整理的粗糙了点)
具体的可以参考原文链接内容,和原文的代码比较详细

欢迎指正!!!!

今天的文章【python笔记】tomotopy | 速度最快的LDA主题模型分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/87508.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注