本文作者:合肥工业大学 电子商务研究所 钱洋 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