分层Dirichlet过程Gensim主题编号独立于语料库大小

时间:2015-07-21 15:34:47

标签: python nlp lda gensim

我在一组文件上使用Gensim HDP模块。

>>> hdp = models.HdpModel(corpusB, id2word=dictionaryB)
>>> topics = hdp.print_topics(topics=-1, topn=20)
>>> len(topics)
150
>>> hdp = models.HdpModel(corpusA, id2word=dictionaryA)
>>> topics = hdp.print_topics(topics=-1, topn=20)
>>> len(topics)
150
>>> len(corpusA)
1113
>>> len(corpusB)
17

为什么主题数量与语料库长度无关?

7 个答案:

答案 0 :(得分:10)

由于 gensim API更改,上面的@Aaron代码被破坏了。我重写并简化如下。自2017年6月开始使用 gensim v2.1.0

import pandas as pd

def topic_prob_extractor(gensim_hdp):
    shown_topics = gensim_hdp.show_topics(num_topics=-1, formatted=False)
    topics_nos = [x[0] for x in shown_topics ]
    weights = [ sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos ]

    return pd.DataFrame({'topic_id' : topics_nos, 'weight' : weights})

答案 1 :(得分:4)

@ Aron&和@Roko Mijic的方法忽略了这样一个事实:函数show_topics默认返回每个主题的前20个单词。如果返回构成主题的所有单词,则该情况下的所有近似主题概率将为1(或0.999999)。我尝试了以下代码,这是@Roko Mijic的改编:

def topic_prob_extractor(gensim_hdp, t=-1, w=25, isSorted=True):
    """
    Input the gensim model to get the rough topics' probabilities
    """
    shown_topics = gensim_hdp.show_topics(num_topics=t, num_words=w ,formatted=False)
    topics_nos = [x[0] for x in shown_topics ]
    weights = [ sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos ]
    if (isSorted):
        return pd.DataFrame({'topic_id' : topics_nos, 'weight' : weights}).sort_values(by = "weight", ascending=False);
    else:
        return pd.DataFrame({'topic_id' : topics_nos, 'weight' : weights});

更好,但我不确定100%有效,方法是提到here的方法。你可以得到主题' HDP模型的真实权重(alpha矢量)为:

alpha = hdpModel.hdp_to_lda()[0];

检查主题'等效的alpha值比计算每个主题的前20个单词的权重以估计其在数据中的使用概率更合乎逻辑。

答案 2 :(得分:3)

@ user3907335在这里完全正确:HDP将计算与指定的截断级别一样多的主题。 然而,可能是这些主题中的许多主题基本上没有发生概率的情况。为了在我自己的工作中帮助解决这个问题,我写了一个方便的小函数,它可以粗略估计与每个主题相关的概率权重。请注意,这只是一个粗略的指标:它没有考虑与每个单词相关的概率。即便如此,它提供了一个非常好的指标,主题是有意义的,而且不是:

with es as(
select *
from foo
where e1 not in (SELECT t1.e1
  FROM foo as t1 
  inner join foo as t2
  on t1.e1=t2.e1 and (t2.c1-t1.c2)=1)
union all
SELECT t1.e1
      ,t1.c1
      ,isnull(t2.c2, t1.c2) as c2
  FROM foo as t1 
  inner join foo as t2
  on t1.e1=t2.e1 and (t2.c1-t1.c2)=1 
 )
 select * from es
 where e1 is not null

我假设您已经知道如何计算HDP模型。一旦你有一个由gensim计算的hdp模型,你可以按如下方式调用该函数:

import pandas as pd
import numpy as np 

def topic_prob_extractor(hdp=None, topn=None):
    topic_list = hdp.show_topics(topics=-1, topn=topn)
    topics = [int(x.split(':')[0].split(' ')[1]) for x in topic_list]
    split_list = [x.split(' ') for x in topic_list]
    weights = []
    for lst in split_list:
        sub_list = []
        for entry in lst: 
            if '*' in entry: 
                sub_list.append(float(entry.split('*')[0]))
        weights.append(np.asarray(sub_list))
    sums = [np.sum(x) for x in weights]
    return pd.DataFrame({'topic_id' : topics, 'weight' : sums})

答案 3 :(得分:2)

我没有将gensim用于HDP,但是较小的语料库中的大多数主题是否有可能发生极低的概率?你能尝试打印主题概率吗?也许,主题数组的长度并不一定意味着所有这些主题实际上都在语料库中找到。

答案 4 :(得分:2)

我认为您误解了被调用方法执行的操作。您可以直接从文档中看到:

  

show_topics()的别名,用于打印主题要记录的主题数量的前n个最可能单词。设置topics = -1以打印所有主题。

您训练模型时未指定主题数量的截断级别,默认值为150.使用print_topics调用topics=-1您将获得每个主题的前20个单词,在你的情况下150个主题。

我还是图书馆的新手,所以也许我'错

答案 5 :(得分:2)

Gensim(版本3.8.3)中显然存在一个错误,其中将-1赋予show_topics根本不返回任何内容。因此,我调整了 Roko Mijic aaron 的答案。

def topic_prob_extractor(gensim_hdp):
    shown_topics = gensim_hdp.show_topics(num_topics=gensim_hdp.m_T, formatted=False)
    topics_nos = [x[0] for x in shown_topics ]
    weights = [ sum([item[1] for item in shown_topics[topicN][1]]) for topicN in topics_nos ]
    return pd.DataFrame({'topic_id' : topics_nos, 'weight' : weights})

答案 6 :(得分:0)

从HDP主题在单个文本级别的连贯性得出平均连贯性是一种排序(并可能截断)它们的方法。以下功能可以做到这一点:

def order_subset_by_coherence(dirichlet_model, bow_corpus, num_topics=10, num_keywords=10):
    """
    Orders topics based on their average coherence across the corpus

    Parameters
    ----------
        dirichlet_model : gensim.models.hdpmodel.HdpModel
        bow_corpus : list of lists (contains (id, freq) tuples)
        num_topics : int (default=10)
        num_keywords : int (default=10)

    Returns
    -------
        ordered_topics: list of lists containing topic tokens
    """
    shown_topics = dirichlet_model.show_topics(num_topics=150, # return all topics
                                               num_words=num_keywords,
                                               formatted=False)
    model_topics = [[word[0] for word in topic[1]] for topic in shown_topics]
    topic_corpus = dirichlet_model.__getitem__(bow=bow_corpus, eps=0) # cutoff probability to 0 

    topics_per_response = [response for response in topic_corpus]
    flat_topic_coherences = [item for sublist in topics_per_response for item in sublist]

    significant_topics = list(set([t_c[0] for t_c in flat_topic_coherences])) # those that appear
    topic_averages = [sum([t_c[1] for t_c in flat_topic_coherences if t_c[0] == topic_num]) / len(bow_corpus) \
                      for topic_num in significant_topics]

    topic_indexes_by_avg_coherence = [tup[0] for tup in sorted(enumerate(topic_averages), key=lambda i:i[1])[::-1]]
    significant_topics_by_avg_coherence = [significant_topics[i] for i in topic_indexes_by_avg_coherence]
    ordered_topics = [model_topics[i] for i in significant_topics_by_avg_coherence][:num_topics] # truncate if desired

    return ordered_topics

可以在this answer中找到该函数的一个版本,其中包括与用于生成语料库的关键字(标签)的主题相关的平均相干性输出。在this answer中可以找到针对各个文本的关键字的类似过程。