具有先前主题词的潜在狄利克雷分配
Latent Dirichlet Allocation with prior topic words
上下文
我正在尝试使用 Latent Dirichlet allocation from Scikit-Learn's decomposition module 从一组文本中提取主题。
这非常有效,除了主题词的质量 found/selected.
在 Li et al (2017) 的一篇文章中,作者描述了使用先前的主题词作为 LDA 的输入。他们手动选择 4 个主题和这些主题的主要词 associated/belonging。对于这些词,他们将相关主题的默认值设置为高数字,将其他主题的默认值设置为 0。对于所有主题 (1),所有其他词(不是为主题手动选择的)都被赋予相同的值。此值矩阵用作 LDA 的输入。
我的问题
如何使用自定义的默认值矩阵(先前的主题词)作为输入,使用 Scikit-Learn 的 LatentDirichletAllocation 模块创建类似的分析?
(我知道有一个 topic_word_prior
参数,但它只需要一个浮点数而不是具有不同 'default values' 的矩阵。)
编辑
解决方案
在@Anis 的帮助下,我创建了原始模块的子class,并编辑了设置起始值矩阵的函数。对于您希望作为输入提供的所有先前主题词,它通过将值与该(先前)词的主题值相乘来转换 components_
矩阵。
这是代码:
# List with prior topic words as tuples
# (word index, [topic values])
prior_topic_words = []
# Example (word at index 3000 belongs to topic with index 0)
prior_topic_words.append(
(3000, [(np.finfo(np.float64).max/4),0.,0.,0.,0.])
)
# Custom subclass for PTW-guided LDA
from sklearn.utils import check_random_state
from sklearn.decomposition._online_lda import _dirichlet_expectation_2d
class PTWGuidedLatentDirichletAllocation(LatentDirichletAllocation):
def __init__(self, n_components=10, doc_topic_prior=None, topic_word_prior=None, learning_method=’batch’, learning_decay=0.7, learning_offset=10.0, max_iter=10, batch_size=128, evaluate_every=-1, total_samples=1000000.0, perp_tol=0.1, mean_change_tol=0.001, max_doc_update_iter=100, n_jobs=None, verbose=0, random_state=None, n_topics=None, ptws=None):
super(PTWGuidedLatentDirichletAllocation, self).__init__(n_components, doc_topic_prior, topic_word_prior, learning_method, learning_decay, learning_offset, max_iter, batch_size, evaluate_every, total_samples, perp_tol, mean_change_tol, max_doc_update_iter, n_jobs, verbose, random_state, n_topics)
self.ptws = ptws
def _init_latent_vars(self, n_features):
"""Initialize latent variables."""
self.random_state_ = check_random_state(self.random_state)
self.n_batch_iter_ = 1
self.n_iter_ = 0
if self.doc_topic_prior is None:
self.doc_topic_prior_ = 1. / self.n_topics
else:
self.doc_topic_prior_ = self.doc_topic_prior
if self.topic_word_prior is None:
self.topic_word_prior_ = 1. / self.n_topics
else:
self.topic_word_prior_ = self.topic_word_prior
init_gamma = 100.
init_var = 1. / init_gamma
# In the literature, this is called `lambda`
self.components_ = self.random_state_.gamma(
init_gamma, init_var, (self.n_topics, n_features))
# Transform topic values in matrix for prior topic words
if self.ptws is not None:
for ptw in self.ptws:
word_index = ptw[0]
word_topic_values = ptw[1]
self.components_[:, word_index] *= word_topic_values
# In the literature, this is `exp(E[log(beta)])`
self.exp_dirichlet_component_ = np.exp(
_dirichlet_expectation_2d(self.components_))
启动与原来的LatentDirichletAllocation
class相同,但现在您可以使用ptws
参数提供先前的主题词。
在查看了源代码和文档之后,在我看来最简单的事情就是继承 LatentDirichletAllocation
并且只重写 _init_latent_vars
方法。就是在fit
中调用的方法创建了components_
属性,也就是分解使用的矩阵。通过重新实现这个方法,你可以按照你想要的方式设置它,特别是提高相关 topics/features 的先验权重。您将在那里重新实现论文的初始化逻辑。
上下文
我正在尝试使用 Latent Dirichlet allocation from Scikit-Learn's decomposition module 从一组文本中提取主题。 这非常有效,除了主题词的质量 found/selected.
在 Li et al (2017) 的一篇文章中,作者描述了使用先前的主题词作为 LDA 的输入。他们手动选择 4 个主题和这些主题的主要词 associated/belonging。对于这些词,他们将相关主题的默认值设置为高数字,将其他主题的默认值设置为 0。对于所有主题 (1),所有其他词(不是为主题手动选择的)都被赋予相同的值。此值矩阵用作 LDA 的输入。
我的问题
如何使用自定义的默认值矩阵(先前的主题词)作为输入,使用 Scikit-Learn 的 LatentDirichletAllocation 模块创建类似的分析?
(我知道有一个 topic_word_prior
参数,但它只需要一个浮点数而不是具有不同 'default values' 的矩阵。)
编辑
解决方案
在@Anis 的帮助下,我创建了原始模块的子class,并编辑了设置起始值矩阵的函数。对于您希望作为输入提供的所有先前主题词,它通过将值与该(先前)词的主题值相乘来转换 components_
矩阵。
这是代码:
# List with prior topic words as tuples
# (word index, [topic values])
prior_topic_words = []
# Example (word at index 3000 belongs to topic with index 0)
prior_topic_words.append(
(3000, [(np.finfo(np.float64).max/4),0.,0.,0.,0.])
)
# Custom subclass for PTW-guided LDA
from sklearn.utils import check_random_state
from sklearn.decomposition._online_lda import _dirichlet_expectation_2d
class PTWGuidedLatentDirichletAllocation(LatentDirichletAllocation):
def __init__(self, n_components=10, doc_topic_prior=None, topic_word_prior=None, learning_method=’batch’, learning_decay=0.7, learning_offset=10.0, max_iter=10, batch_size=128, evaluate_every=-1, total_samples=1000000.0, perp_tol=0.1, mean_change_tol=0.001, max_doc_update_iter=100, n_jobs=None, verbose=0, random_state=None, n_topics=None, ptws=None):
super(PTWGuidedLatentDirichletAllocation, self).__init__(n_components, doc_topic_prior, topic_word_prior, learning_method, learning_decay, learning_offset, max_iter, batch_size, evaluate_every, total_samples, perp_tol, mean_change_tol, max_doc_update_iter, n_jobs, verbose, random_state, n_topics)
self.ptws = ptws
def _init_latent_vars(self, n_features):
"""Initialize latent variables."""
self.random_state_ = check_random_state(self.random_state)
self.n_batch_iter_ = 1
self.n_iter_ = 0
if self.doc_topic_prior is None:
self.doc_topic_prior_ = 1. / self.n_topics
else:
self.doc_topic_prior_ = self.doc_topic_prior
if self.topic_word_prior is None:
self.topic_word_prior_ = 1. / self.n_topics
else:
self.topic_word_prior_ = self.topic_word_prior
init_gamma = 100.
init_var = 1. / init_gamma
# In the literature, this is called `lambda`
self.components_ = self.random_state_.gamma(
init_gamma, init_var, (self.n_topics, n_features))
# Transform topic values in matrix for prior topic words
if self.ptws is not None:
for ptw in self.ptws:
word_index = ptw[0]
word_topic_values = ptw[1]
self.components_[:, word_index] *= word_topic_values
# In the literature, this is `exp(E[log(beta)])`
self.exp_dirichlet_component_ = np.exp(
_dirichlet_expectation_2d(self.components_))
启动与原来的LatentDirichletAllocation
class相同,但现在您可以使用ptws
参数提供先前的主题词。
在查看了源代码和文档之后,在我看来最简单的事情就是继承 LatentDirichletAllocation
并且只重写 _init_latent_vars
方法。就是在fit
中调用的方法创建了components_
属性,也就是分解使用的矩阵。通过重新实现这个方法,你可以按照你想要的方式设置它,特别是提高相关 topics/features 的先验权重。您将在那里重新实现论文的初始化逻辑。