当前位置: 代码迷 >> 综合 >> Partially Labeled Dirichlet Allocation(PLDA)算法的理解与编程细节(Java)
  详细解决方案

Partially Labeled Dirichlet Allocation(PLDA)算法的理解与编程细节(Java)

热度:50   发布时间:2023-12-15 20:00:47.0

本文作者:合肥工业大学 电子商务研究所 钱洋 email:1563178220@qq.com 。
内容可能有不到之处,欢迎交流

未经本人允许禁止转载

文章目录

  • 论文来源
  • 模型
  • 公式推理
  • 编程细节
    • 数据编码
    • 初始化
    • 轮盘赌采样主题
  • 数据可能导致的问题和处理
  • 完整代码

论文来源

Ramage D, Manning C D, Dumais S. Partially labeled topic models for interpretable text mining[C]//Proceedings of the 17th ACM SIGKDD international conference on Knowledge discovery and data mining. ACM, 2011: 457-465.

论文来自于11年,KDD会议。

作者在这篇论文所提的模型,是Labeled LDA的简单变形。并且Labeled LDA也是该作者提出来的。

Ramage D, Hall D, Nallapati R, et al. Labeled LDA: A supervised topic model for credit attribution in multi-labeled corpora[C]//Proceedings of the 2009 Conference on Empirical Methods in Natural Language Processing: Volume 1-Volume 1. Association for Computational Linguistics, 2009: 248-256.

在本人之前的博客中,已经介绍了Labeled LDA和其编程细节,博客地址为:
https://qianyang-hfut.blog.csdn.net/article/details/90771054

模型

在Labeled LDA模型中,使用标签来控制文档的主题,即模型是有监督的。但是,Labeled LDA假设一个标签只对应一个主题。因此,模型的主题数目就是所有文档包含的标签数目。

但在PLDA中,假设每个标签对应多个主题。例如,语料共有 L L L个标签,每个标签如果对 K l K_l Kl?个主题,则总的主题数目为 K = L ? K l K = L*K_l K=L?Kl?

另外,在该模型中,还假设了一个背景类,其对应一些背景主题。在作者的实验中:
在这里插入图片描述

下面,看一下模型的概率图:
在这里插入图片描述

在来看一下Labeled LDA模型的概率图表示:
在这里插入图片描述
其本质并没有多大变化,只相当于对将每个标签对应一个主题,变成了一个标签对应多个主题。另外,可以对每个文档引入一个背景标签。

PLDA的核心假设是每个主题只对应一个标签,文档的标签决定了文档的主题,主题生成了文档的词汇。

公式推理

在论文中,采样文档某词对应的主题和标签,采用下面的公式:
在这里插入图片描述
从第一个“正比于”转化成第二个“正比于”的原因是一个主题只参与一个标签,因此,我们只要追踪主题的变化就行了。

在主题模型的编程中,我们经常使用下面的代码来表示文档某词的主题分配。

public int[][] z;

针对这个模型,我们是不需要表示文档某词的标签分配的,即不需要统计:

public int[][] l;

这个在作者的原文中,也有提及:

  • We do not need to allocate memory to represent which label ~l is assigned to each token.

从公式中,可以看到,采样主题实际统计的量和Labeled LDA一样的,包括文档-主题词统计,文档总词数统计,主题-某词数量统计,主题生成的总词数统计

编程细节

数据编码

在编程中,需要将原始文本(包括标签)进行编号。例如,输入的原始文档如下:
在这里插入图片描述

其中,标签和正文**以"\t"**分割,**标签以标签之间使用“”–“”**分割。

在编程中,可以使用下面两组数据类型,实现原始内容的标号:

public Map<String, Integer> wordToIndexMap = new HashMap<String, Integer>();;  //word to index
public List<String> indexToWordMap = new ArrayList<String>();    //index to String word 
public Map<String, Integer> labelToIndexMap = new HashMap<String, Integer>(); //label to index
public List<String> indexLabelMap = new ArrayList<String>();   //index to String label 

另外,由于一个标签 l l l对应多个主题 K l K_l Kl?,一个主题只对应一个标签。假设所有标签的 K l K_l Kl?都是相等的,即每个标签对应的主题数目是一致的。为此,需要设置一个变量:

public int perlabel_topic; // the latent topics for each label

并且,还要设置一个变量用于存储每个标签对应的主题,即:

public List<int[]> label_topicIndex;

例如,标签每个标签对应3个主题,则封装在label_topicIndex中的数据格式如下:

0	0
0	1
0	2
1	3
1	4
1	5
2	6
2	7
2	8
...

**值得注意的是:**在实际编号过程中,indexLabelMap是不包含背景标签的。因此,在对所有文档标签编号之后,还需要添加一个背景标签,即:

indexLabelMap.add("global label");

初始化

在初始化过程中,我们首先取出文档的标签。之后判断文档是否有标签,如果有标签(除背景标签)。如果有标签,则随机从中抽取一个便签,获取标签对应的多个主题,之后从这些主题中随机选择一个主题。如果没有标签,则从 L L L个标签中选择一个标签,再随机赋值主题(这里也可从 K K K个主题中选一个,不选标签)。如下为其核心操作代码:

				int label;int topic;//randomly initialize a label for the wordif (dLabels.length > 1) {
    label = dLabels[(int) (Math.random() * dLabels.length)];} else {
    label = dLabels[(int) (Math.random() * L)];}//randomly initialize a topic for the wordtopic = label_topicIndex.get(label)[(int) (Math.random() * perlabel_topic)];z[d][n] = topic;updateCount(d, topic, n, +1);

轮盘赌采样主题

在轮盘赌采样主题时,需要主题主题编号的不连续性。例如,该文档对应的标签标号为0和2,则可能选择的主题有:

0,1,2,6,7,8

因此,我们需要增加一个 i n d e x index index变量,使其从0开始统计,计算 p [ ] p[] p[],即:

		double[] p = new double[L_d * perlabel_topic];int index = 0;  // because of the disordered topic numberfor (int l = 0; l < L_d; l++) {
    for (int i = 0; i < perlabel_topic; i++) {
    p[index] = (ndk[d][label_topicIndex.get(doclabel[d][l])[i]] + alpha) / (ndsum[d] + perlabel_topic * alpha) * (nkw[label_topicIndex.get(doclabel[d][l])[i]][docword[d][n]] + beta)/ (nksum[label_topicIndex.get(doclabel[d][l])[i]] + V * beta);index ++;}}index = FuncUtils.rouletteGambling(p); //roulette gambling for updating the topic of a wordint label = index/perlabel_topic;topic = doclabel[d][label] * perlabel_topic + label % perlabel_topic;z[d][n] = topic;updateCount(d, topic, n, +1);  // update the count ++1

数据可能导致的问题和处理

在使用PLDA时,需要注意的一点的标签的稀疏度。如果标签的稀疏度过大(标签数目过多,且共现率较小),则可能导致主题数目过多,学习的主题很差。
在作者的原文中,构造实验使用了两种数据集,一种是文献数据集,一种是del.icio.us数据集,得到的结果如下:
在这里插入图片描述
很明显,这些标签对应的粒度都是很粗的

但在实际的社交网络中,标签往往是由用户自定义的,因此语料可能面临标签过多,稀疏性过大。例如:
在这里插入图片描述

因此,在应用该模型的过程中,需要对标签进行整理(这个是比较耗时的),将相似的标签合并成一个标签,过滤低频标签。

完整代码

关注TopicModel4J(待上传),将提供大量的概率图模型的代码:
https://github.com/soberqian/TopicModel4J

  相关解决方案