使用经过培训的MALLET主题模型从相关主题中提取关键字

时间:2017-06-08 17:02:10

标签: java topic-modeling mallet

我正在尝试使用MALLETTopicInferencer来使用经过训练的模型从任意文本中推断出关键字。到目前为止,我的总体方法如下。

  • 使用大量已知培训数据训练ParallelTopicModel以创建主题集合。我目前正在使用250,000行的培训文件来创建5,000个主题。
  • 从不在训练模型中的任意文本创建InstanceList
  • 使用训练有素的模型topicInferencer.getSampledDistribution根据模型生成未知文本的主题分布。
  • 对返回的分布进行排序,并提取壁橱与未知输入文本匹配的前n个主题的ID。
  • 从每个匹配主题中提取热门关键字。

我的代码如下:

生成ParallelTopicModel

InstanceList instanceList = new InstanceList(makeSerialPipeList());
instanceList.addThruPipe(new SimpleFileLineIterator(trainingFile)); //training file with one entry per line (around 250,000 lines)

//should train a model with the end result being 5000 topics each with a collection of words
ParallelTopicModel parallelTopicModel = new ParallelTopicModel(
    5000, //number of topics, I think with a large sample size we should want a large collection of topics
    1.0D, //todo: alphaSum, really not sure what this does
    0.01D //todo: beta, really not sure what this does
);
parallelTopicModel.setOptimizeInterval(20); //todo: read about this
parallelTopicModel.addInstances(instanceList);
parallelTopicModel.setNumIterations(2000);
parallelTopicModel.estimate();

我的第一组问题与创建ParallelTopicModel有关。

由于我使用的是一个相当大的培训文件,我认为我需要大量的主题。我的逻辑是,主题数量越大,推断的关键字越匹配任意输入文本。

我也不确定alphaSum beta值和迭代次数将如何影响生成的模型。

另一方面,我正在使用ParallelTopicModel来创建推断的主题分布。

TopicInferencer topicInferencer = parallelTopicModel.getInferencer();
String document = //arbitrary text not in trained model
//following the format I found in SimpleFileLineIterator to create an Instance out of a document
Instance instance = new Instance(document, null, new URI("array:" + 1), null);
InstanceList instanceList = new InstanceList(serialPipes); //same SerialPipes used to create the InstanceList used for the ParallelTopicModel
instanceList.addThruPipe(instance);

//this should return the array of topicIDs and the match value
//[topicId] = 0.5 //match value
double[] topicDistribution = 
topicInferencer.getSampledDistribution(instanceList.get(0), //extract text
    2000, //same iteration count used in the model
     1, //todo: thinning, not sure what this does
     5 //todo: burnIn, not sure what this does
);

//returns a sorted list of the top 5 topic IDs
//this should be the index of the largest values in the returned topicDistribution
List<Integer> topIndexes = topIndexes(topicDistribution, 5); //top 5 topic indexes

//list topics and sorted keywords
ArrayList<TreeSet<IDSorter>> sortedWords = parallelTopicModel.getSortedWords();

//loop over the top indexes
topIndexes.forEach(index -> {
    IDSorter idSorter = sortedWords.get(index).first(); //should hopefully be the first keyword in each topic
    //not sure what alphabet I should use here or if it really matters?
    //I passed in the alphabet from the original instance list as well as the one contained on our model
    Object result = parallelTopicModel.getAlphabet().lookupObject(idSorter.getID());
    double weight = idSorter.getWeight();

    String formattedResult = String.format("%s:%.0f", result, weight);
    //I should now have a relevant keyword and a weight in my result
});

我在这里有类似的问题,首先我不完全确定这种整体方法是否正确。

我也不确定我应该使用的是什么Alphabet,用于生成InstanceList的{​​{1}}或ParallelTopicModel直接获得的ParallelTopicModel

我知道这是一个相当复杂的问题,但任何见解都会非常感激!

1 个答案:

答案 0 :(得分:3)

alphaSumbeta:这些控制了您对估计的文档主题和主题词分布的集中程度。较小的值会促使更集中的分布和更少的移动。较大的值可以促进更平坦,更均匀的分布,更多的运动。在物理学术语中,认为“高能量”与“低能量”。

1.0 alphaSum是低端,5.0可能更安全。 beta的0.01几乎总是很好。这并不重要,因为您正在使用超参数优化(setOptimizeInterval)。这将根据估算的主题拟合alpha值。您可能还希望将老化期间设置为小于默认值的值,例如25.这是在开始优化之前扫描数据的次数。

主题数量:即使是250k文本片段,5000也是很多。我从500开始。通过超参数优化,您将获得一些大型的一般主题和许多小的特定主题。我的猜测是,有5000个主题,其中大部分 - 至少一半 - 基本上是空的。这在某种程度上是好的,因为这意味着模型自适应地选择其主题限制。但这也意味着您拥有的主题数据支持非常少,看起来像是随机单词。它还会在推理时产生问题:如果模型看到的文档并不真正适合任何“真实”主题,则可以将其置于空主题中。

推理:2000次迭代对于推断新文档的主题分布来说太过分了。 10应该就够了。给定一个固定的,已经学过的模型的一个文档的抽样主题比从头学习模型更容易 。得到的分布是几个采样状态的平均值。它会在开头忽略burnin个状态,然后在保存的样本之间跳过thinning个状态。

字母表无关紧要。您可以假设相同的id将导致相同的字符串。如果训练字母表和测试字母表不兼容,则推理不起作用。