基于狄利克雷-多项式分布做文档聚类代码(dirichlet multinomial mixture model)

本文介绍了一种基于Dirichlet多项式混合模型(DMM)的短文本聚类方法,该方法通过Gibbs抽样实现主题分配,适用于短文本集合的聚类任务。详细解析了模型初始化和Gibbs抽样的核心代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

论文来源

Yin J, Wang J. A dirichlet multinomial mixture model-based approach for short text clustering[C]//Proceedings of the 20th ACM SIGKDD international conference on Knowledge discovery and data mining. ACM, 2014: 233-242.
计算机顶会KDD上

主要使用的是DMM模型来做短文档的聚类。

论文的理解

关于论文的理解请看我写的另外一篇博客:
http://blog.csdn.net/qy20115549/article/details/79429127

论文核心代码解读

以下为gibbs抽样对应的程序,也是该算法的核心代码,比较容易理解。

//模型初始化
    public void intialize(DocumentSet documentSet)
    {

        D = documentSet.D;  //获取文档总数目
        z = new int[D]; //文档对应的主题数目
        for(int d = 0; d < D; d++){
            //获取每一篇文档的内容
            Document document = documentSet.documents.get(d);
            //针对每一篇文档随机初始化一个主题
            int cluster = (int) (K * Math.random());
            z[d] = cluster;
            //每个主题对应的文档数目统计
            m_z[cluster]++;
            //对文档的每个单词进行循环
            for(int w = 0; w < document.wordNum; w++){
                //获取文档每个单词的编号
                int wordNo = document.wordIdArray[w];
                //获取文档每个单词出现的数目
                int wordFre = document.wordFreArray[w];
                //统计每个主题下,每个单词出现的数目
                n_zv[cluster][wordNo] += wordFre;
                //统计每个主题下所有单词的数目
                n_z[cluster] += wordFre; 
            }
        }
    }
    //gibbs采样
    public void gibbsSampling(DocumentSet documentSet)
    {
        for(int i = 0; i < iterNum; i++){
            //每篇文档循环
            for(int d = 0; d < D; d++){
                Document document = documentSet.documents.get(d);
                //获取文档对应的主题
                int cluster = z[d];
                //移除该文档,该主题对应的文档数目减去1
                m_z[cluster]--;
                for(int w = 0; w < document.wordNum; w++){
                    int wordNo = document.wordIdArray[w];
                    int wordFre = document.wordFreArray[w];
                    //该主题对应的文档中的单词的数目,减少文档该单词出现的数目
                    n_zv[cluster][wordNo] -= wordFre;
                    //该主题对应的单词总数减去了该文档对应单词的总数
                    n_z[cluster] -= wordFre;
                }
                //抽取该文档所属的新主题
                cluster = sampleCluster(d, document);
                //分配该文档对应的新主题后,重新统计相关词频
                z[d] = cluster;
                m_z[cluster]++;
                for(int w = 0; w < document.wordNum; w++){
                    int wordNo = document.wordIdArray[w];
                    int wordFre = document.wordFreArray[w];
                    n_zv[cluster][wordNo] += wordFre; 
                    n_z[cluster] += wordFre; 
                }
            }
        }
    }

    private int sampleCluster(int d, Document document)
    { 
        double[] prob = new double[K];
        //统计是哪个主题
        int[] overflowCount = new int[K];
        //对所有主题进行循环,计算该文档属于每个主题的概率
        for(int k = 0; k < K; k++){
            //依照计算公式计算文档d属于每个单词的概率
            prob[k] = (m_z[k] + alpha) / (D - 1 + alpha0);
            double valueOfRule2 = 1.0;
            int i = 0;
            for(int w=0; w < document.wordNum; w++){
                //获取该文档中某一单词的编号及出现的频率
                int wordNo = document.wordIdArray[w];
                int wordFre = document.wordFreArray[w];
                //文档的每个单词进行计算,这里有防止连乘积概率过小的判断及处理
                for(int j = 0; j < wordFre; j++){
                    if(valueOfRule2 < smallDouble){
                        overflowCount[k]--;
                        valueOfRule2 *= largeDouble;
                    }
                    valueOfRule2 *= (n_zv[k][wordNo] + beta + j) 
                             / (n_z[k] + beta0 + i);
                    i++;
                }
            }
            prob[k] *= valueOfRule2;            
        }
        //重新计算概率
        reComputeProbs(prob, overflowCount, K);
        //使用轮盘赌,分配新的主题
        for(int k = 1; k < K; k++){
            prob[k] += prob[k - 1];
        }
        double thred = Math.random() * prob[K - 1];
        int kChoosed;
        for(kChoosed = 0; kChoosed < K; kChoosed++){
            if(thred < prob[kChoosed]){
                break;
            }
        }

        return kChoosed;
    }
    //重新计算概率值
    private void reComputeProbs(double[] prob, int[] overflowCount, int K)
    {
        int max = Integer.MIN_VALUE;
        for(int k = 0; k < K; k++){
            if(overflowCount[k] > max && prob[k] > 0){
                max = overflowCount[k];
                System.out.println("max:"+max);
            }
        }
        //概率值统一扩展
        for(int k = 0; k < K; k++){         
            if(prob[k] > 0){
                prob[k] = prob[k] * Math.pow(largeDouble, overflowCount[k] - max);
            }
        }       
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值