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

Java 使用经过训练的MALLET主题模型从相关主题中提取关键字,java,topic-modeling,mallet,Java,Topic Modeling,Mallet,我正试图使用的TopicInferencer使用经过训练的模型从任意文本中推断关键字。到目前为止,我的总体方法如下 使用大量已知的训练数据训练一个ParallelTopicModel,以创建一个主题集合。我目前正在使用一个250000行的培训文件来创建5000个主题 从不在训练模型中的任意文本创建一个实例列表 使用经过训练的模型的主题引用器.getSampledDistribution生成针对模型的未知文本的主题分发 对返回的分发内容进行排序,并提取与未知输入文本匹配的顶部n主题的ID 从每个

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

  • 使用大量已知的训练数据训练一个
    ParallelTopicModel
    ,以创建一个主题集合。我目前正在使用一个250000行的培训文件来创建5000个主题
  • 从不在训练模型中的任意文本创建一个
    实例列表
  • 使用经过训练的模型的
    主题引用器.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
});
TopicInferencer TopicInferencer=parallelTopicModel.getInferencer();
字符串文档=//任意文本不在训练模型中
//按照我在SimpleFileLineIterator中找到的格式,从文档中创建一个实例
实例实例=新实例(文档,null,新URI(“数组:”+1),null);
InstanceList InstanceList=新InstanceList(串行管道)//与用于创建用于ParallelTopicModel的InstanceList的SerialPipes相同
instanceList.addThruPipe(实例);
//这将返回topicid数组和匹配值
//[topicId]=0.5//匹配值
双[]主题分布=
topicInferencer.getSampledDistribution(instanceList.get(0))//提取文本
2000,//与模型中使用的迭代计数相同
1,//todo:变薄,不确定这是做什么的
5//todo:burnIn,不知道这是干什么的
);
//返回前5个主题ID的排序列表
//这应该是返回的主题分布中最大值的索引
列表topIndexes=topIndexes(topicDistribution,5)//五大主题索引
//列出主题和已排序的关键字
ArrayList sortedWords=parallelTopicModel.getSortedWords();
//循环顶部索引
topIndexes.forEach(索引->{
IDSorter IDSorter=sortedWords.get(index).first();//应该是每个主题中的第一个关键字
//不确定我应该在这里使用什么字母,或者它是否真的很重要?
//我传入了原始实例列表中的字母表以及模型中包含的字母表
对象结果=parallelTopicModel.getAlphabet().lookupObject(idSorter.getID());
double-weight=idSorter.getWeight();
String formattedResult=String.format(“%s:%.0f”,结果,权重);
//我现在应该有一个相关的关键字和权重在我的结果
});
我这里有一组类似的问题,首先我不完全确定这个整体方法是否正确

我也不确定我应该使用什么
字母表
,从我的
实例列表
中用来生成
ParallelTopicModel
的字母表,或者直接从
ParallelTopicModel
中获得的字母表


我知道这是一个相当复杂的问题,但任何见解都将不胜感激

alphaSum
beta
:它们控制您希望估计的文档主题和主题词分布的集中程度。值越小,分布越集中,移动越少。值越大,分布越平坦、越均匀,移动越大。用物理学的术语来说,想想“高能”和“低能”

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

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

推断:2000次迭代对于推断新文档的主题分布来说太多了。10个就足够了。给定一个固定的、已经学习过的模型,为一个文档抽取主题要比从头开始学习模型容易得多。结果分布是几个采样状态的平均值。它将忽略开始时的
burnin
状态,然后跳过保存的样本之间的
细化
状态

字母表不重要。您可以假设相同的id将产生相同的字符串。如果训练字母表和测试字母表不兼容,推理就不起作用