深度学习与自然语言处理第三次作业——LDA段落主题分布问题

利用LDA模型解决段落主体分布问题



一、解题背景

从给定的语料库中均匀抽取200个段落(每个段落大于500个词), 每个段落的标签就是对应段落所属的小说。利用LDA模型对于文本建模,并把每个段落表示为主题分布后进行分类。验证与分析分类结果。


二、解题原理

1、LDA描述

LDA(Linear Discriminant Analysis),是一种文档主题生成模型,,它可以将文档中每篇文档的主题按照概率分布的形式给出。也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档到主题服从多项式分布,主题到词服从多项式分布。

LDA是一种非监督机器学习技术,可以用来识别大规模文档集(document collection)或语料库(corpus)中潜藏的主题信息。它采用了词袋(bag of words)的方法,这种方法将每一篇文档视为一个词频向量,从而将文本信息转化为了易于建模的数字信息。但是词袋方法没有考虑词与词之间的顺序,这简化了问题的复杂性,同时也为模型的改进提供了契机。每一篇文档代表了一些主题所构成的一个概率分布,而每一个主题又代表了很多单词所构成的一个概率分布。

LDA的核心思想是寻找到最佳的投影方法,将高维的样本投影到特征空间(feature space),使得不同类别间的数据“距离”最大,而同一类别内的数据“距离”最小。

2、LDA模型生成

首先定义文章集合为 D o c Doc Doc,文章主题集合为 T o p i c Topic Topic D o c Doc Doc中的每个文档 d o c doc doc可以看作为一个单词序列 < w 1 , w 2 , . . . , w n > <w_1,w_2,...,w_n> <w1,w2,...,wn>,其中 w i w_i wi表示为第 i i i个单词, d o c doc doc共有 n n n个单词。
D o c Doc Doc中的所有不同单词组成一个集合 V o c Voc Voc,LDA模型以文档集合 D o c Doc Doc作为输入,最终训练处两个结果向量, k k k表示Topi词, m m m表示 V o c Voc Voc中包含的词语数量。
对每个 D o c Doc Doc中对应到不同 T o p i c Topic Topic的概率 θ d = < p t 1 , . . . , p t k > \theta_d=<p_{t_1},...,p_{t_k}> θd=<pt1,...,ptk>,其中 p t i p_{t_i} pti表示 d o c doc doc对应 T o p i c Topic Topic中第 i i i个Topic词的概率。
其中 p t i = n t i n p_{t_i}=\frac{n_{t_i}}{n} pti=nnti n t i n_{t_i} nti表示 d o c doc doc中对应的第 i i i个Topic的词的数目, n n n表示 d o c doc doc中所有词的总数。

对每个 T o p i c Topic Topic中的Topic,生成不同单词的概率 φ t = < p w 1 , . . . , p w m > \varphi_t=<p_{w_1},...,p_{w_m}> φt=<pw1,...,pwm>,其中 p w i p_{w_i} pwi表示 t t t生成 V o c Voc Voc中的第 i i i个单词的概率。
其中 p w i = N w i N p_{w_i}=\frac{N_{w_i}}{N} pwi=NNwi N w i N_{w_i} Nwi表示对应到Topic的 V o c Voc Voc中的第 i i i个单词的数目, N N N表示所有对应到Topic的单词总数。
LDA 的核心公式如下所示:
P ( 词 ∣ 文 档 ) = P ( 词 ∣ 主 题 ) ∗ P ( 主 题 ∣ 文 档 ) P(词|文档)=P(词|主题)*P(主题|文档) P()=P()P()
P ( w ∣ d ) = P ( w ∣ t ) ∗ P ( t ∣ d ) P(w|d)=P(w|t)*P(t|d) P(wd)=P(wt)P(td)

公式以Topic作为中间层,通过当前的 θ d \theta_d θd φ t \varphi_t φt给出了文档 d d d中出现单词 w w w的概率。其中的 P ( t ∣ d ) P(t|d) P(td)可通过 θ d \theta_d θd计算得到, P ( w ∣ t ) P(w|t) P(wt)利用 φ t \varphi_t φt计算得到。因此,我们利用当前的 θ d \theta_d θd φ t \varphi_t φt,我们可以为一个文档中的单词计算它对应任意一个Topic时的 P ( w ∣ d ) P(w|d) P(wd)值,然后根据这些结果来更新这个词对应的Topic。相对应的,如果这个更新改变了这个单词所对应的Topic值,反过来也会影响 θ d \theta_d θd φ t \varphi_t φt


三、实验分析

1、语料处理

题目要求均匀抽取200个段落(每个段落大于500个词), 每个段落的标签就是对应段落所属的小说。
对给定语料库进行分析可知,语料库内共有16篇文章,从每一篇文章内抽取13个段落,共有208个段落;对每篇文章分词之后,将一篇文章的总词数除以13,即每篇文章共有13个区间,所选取的段落为每个区间抽取前500个词

代码如下(读取语料内容):

def read_novel(path):  # 读取语料内容
    content = []
    names = os.listdir(path)
    for name in names:
            con_temp = []
            novel_name = path + '\\' + name
            with open(novel_name, 'r', encoding='ANSI') as f:
                con = f.read()
                con = content_deal(con)
                con = jieba.lcut(con)  # 结巴分词
                con_list = list(con)
                pos = int(len(con)//13) ####16篇文章,分词后,每篇均匀选取13个500词段落进行建模
                for i in range(13):
                    con_temp = con_temp + con_list[i*pos:i*pos+500]
                content.append(con_temp)
            f.close()
    return content, names

代码如下(语料预处理):

def content_deal(content):  # 语料预处理,进行断句,去除一些广告和无意义内容
    ad = ['本书来自www.cr173.com免费txt小说下载站\n更多更新免费电子书请关注www.cr173.com', '----〖新语丝电子文库(www.xys.org)〗', '新语丝电子文库',
          '\u3000', '\n', '。', '?', '!', ',', ';', ':', '、', '《', '》', '“', '”', '‘', '’', '[', ']', '....', '......',
          '『', '』', '(', ')', '…', '「', '」', '\ue41b', '<', '>', '+', '\x1a', '\ue42b']
    for a in ad:
        content = content.replace(a, '')
    return content

2、模型训练

首先进行初始化,每篇文章的每个词语随机赋予一个初始的Topic值,然后分别统计每篇文章的总词数、每篇文章的词频、每个Topic的总词数、每个Topic的词频;
再计算每个topic被选中的概率,然后进行迭代,训练模型,具体步骤如下所示:

代码如下(模型训练):

    [data_txt, files] = read_novel("金庸小说集")
    Topic_All = []  # 每篇文章中的每个词来自哪个topic
    Topic_count = {}  # 每个topic有多少词
    Topic_fre0 = {}; Topic_fre1 = {}; Topic_fre2 = {}; Topic_fre3 = {};
    Topic_fre4 = {}; Topic_fre5 = {}; Topic_fre6 = {}; Topic_fre7 = {};
    Topic_fre8 = {}; Topic_fre9 = {}; Topic_fre10 = {}; Topic_fre11 = {};
    Topic_fre12 = {}; Topic_fre13 = {}; Topic_fre14 = {}; Topic_fre15 = {}  # 每个topic的词频
    Doc_count = []  # 每篇文章中有多少个词
    Doc_fre = []  # 每篇文章有多少各个topic的词
    i = 0
    for data in data_txt:
        topic = []
        docfre = {}
        for word in data:
            a = random.randint(0, len(data_txt)-1)  # 为每个单词赋予一个随机初始topic
            topic.append(a)
            if '\u4e00' <= word <= '\u9fa5':
                Topic_count[a] = Topic_count.get(a, 0) + 1  # 统计每个topic总词数
                docfre[a] = docfre.get(a, 0) + 1  # 统计每篇文章的词频
                exec('Topic_fre{}[word]=Topic_fre{}.get(word, 0) + 1'.format(i, i))  # 统计每个topic的词频
        Topic_All.append(topic)
        docfre = list(dict(sorted(docfre.items(), key=lambda x: x[0], reverse=False)).values())
        Doc_fre.append(docfre)
        Doc_count.append(sum(docfre))  # 统计每篇文章的总词数
        # exec('print(len(Topic_fre{}))'.format(i))
        i += 1
    Topic_count = list(dict(sorted(Topic_count.items(), key=lambda x: x[0], reverse=False)).values())
    # print(Topic_All[0])
    Doc_fre = np.array(Doc_fre)  # 转为array方便后续计算
    Topic_count = np.array(Topic_count)  # 转为array方便后续计算
    Doc_count = np.array(Doc_count)  # 转为array方便后续计算
    print(Doc_fre)
    print(Topic_count)
    print(Doc_count)
    # print(Topic_fre0)
    Doc_pro = []  # 每个topic被选中的概率
    Doc_pronew = []  # 记录每次迭代后每个topic被选中的新概率
    for i in range(len(data_txt)):
        doc = np.divide(Doc_fre[i], Doc_count[i])
        Doc_pro.append(doc)
    Doc_pro = np.array(Doc_pro)
    print(Doc_pro)
    stop = 0  # 迭代停止标志
    loopcount = 1  # 迭代次数
    while stop == 0:
        i = 0
        for data in data_txt:
            top = Topic_All[i]
            for w in range(len(data)):
                word = data[w]
                pro = []
                topfre = []
                if '\u4e00' <= word <= '\u9fa5':
                    for j in range(len(data_txt)):
                        exec('topfre.append(Topic_fre{}.get(word, 0))'.format(j))  # 读取该词语在每个topic中出现的频数
                    pro = Doc_pro[i] * topfre / Topic_count  # 计算每篇文章选中各个topic的概率乘以该词语在每个topic中出现的概率,得到该词出现的概率向量
                    m = np.argmax(pro)  # 认为该词是由上述概率之积最大的那个topic产生的
                    Doc_fre[i][top[w]] -= 1  # 更新每个文档有多少各个topic的词
                    Doc_fre[i][m] += 1
                    Topic_count[top[w]] -= 1  # 更新每个topic的总词数
                    Topic_count[m] += 1
                    exec('Topic_fre{}[word] = Topic_fre{}.get(word, 0) - 1'.format(top[w], top[w]))  # 更新每个topic该词的频数
                    exec('Topic_fre{}[word] = Topic_fre{}.get(word, 0) + 1'.format(m, m))
                    top[w] = m
            Topic_All[i] = top
            i += 1
        print(Doc_fre, 'new')
        print(Topic_count, 'new')
        if loopcount == 1:  # 计算新的每篇文章选中各个topic的概率
            for i in range(len(data_txt)):
                doc = np.divide(Doc_fre[i], Doc_count[i])
                Doc_pronew.append(doc)
            Doc_pronew = np.array(Doc_pronew)
        else:
            for i in range(len(data_txt)):
                doc = np.divide(Doc_fre[i], Doc_count[i])
                Doc_pronew[i] = doc
        print(Doc_pro)
        print(Doc_pronew)
        if (Doc_pronew == Doc_pro).all():  # 如果每篇文章选中各个topic的概率不再变化,则认为模型已经训练完毕
            stop = 1
        else:
            Doc_pro = Doc_pronew.copy()
        loopcount += 1
    print(Doc_pronew)  # 输出最终训练的到的每篇文章选中各个topic的概率
    print(loopcount)  # 输出迭代次数
    # print(Doc_pro0)
    # print(Doc_pronew0)
    print('模型训练完毕!')

3、模型测试

仍然在对应的16部小说中选择段落作为测试集,在之前训练集中选取的是208个段落中的第0-500个单词,因此在测试集中选取第501-1000单词形成测试段落,最终形成待分类文章。

def read_novel1(path):  # 读取语料内容——测试集
    content = []
    names = os.listdir(path)
    for name in names:
            con_temp = []
            novel_name = path + '\\' + name
            with open(novel_name, 'r', encoding='ANSI') as f:
                con = f.read()
                con = content_deal(con)
                con = jieba.lcut(con)  # 结巴分词
                con_list = list(con)
                pos = int(len(con)//13) ####16篇文章,分词后,每篇均匀选取13个500词段落进行建模
                for i in range(13):
                    con_temp = con_temp + con_list[i*pos+501:i*pos+1000]##测试集
                content.append(con_temp)
            f.close()
    return content, names

首先仍然在读取后对15篇待分类文章进行预处理,之后将15篇待分类文章中的每个词赋予一个随机的初始Topic,并同样统计每篇文章的总词数、每篇文章的词频,分别记录下来,但此时与模型训练时不同的是,每个Topic的总词数、每个Topic的词频,将不再需要统计,这两个量是模型训练已经完成了的,将作为已知量来对数据进行测试。

接下来,则需要根据这些概率结果,区分每篇待分类文章究竟来自哪一本小说,此处采用的是欧式距离的方式,即比较待分类文章与已知的小说,两者对于各个Topic的概率向量之间的距离最近,即认为是来自该本小说。

    [test_txt, files] = read_novel("金庸小说集")
    Doc_count_test = []  # 每篇文章中有多少个词
    Doc_fre_test = []  # 每篇文章有多少各个topic的词
    Topic_All_test = []  # 每篇文章中的每个词来自哪个topic
    i = 0
    for data in test_txt:
        topic = []
        docfre = {}
        for word in data:
            a = random.randint(0, len(data_txt) - 1)  # 为每个单词赋予一个随机初始topic
            topic.append(a)
            if '\u4e00' <= word <= '\u9fa5':
                docfre[a] = docfre.get(a, 0) + 1  # 统计每篇文章的词频
        Topic_All_test.append(topic)
        docfre = list(dict(sorted(docfre.items(), key=lambda x: x[0], reverse=False)).values())
        Doc_fre_test.append(docfre)
        Doc_count_test.append(sum(docfre))  # 统计每篇文章的总词数
        i += 1
    # print(Topic_All[0])
    Doc_fre_test = np.array(Doc_fre_test)
    Doc_count_test = np.array(Doc_count_test)
    print(Doc_fre_test)
    print(Doc_count_test)
    Doc_pro_test = []  # 每个topic被选中的概率
    Doc_pronew_test = []  # 记录每次迭代后每个topic被选中的新概率
    for i in range(len(test_txt)):
        doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
        Doc_pro_test.append(doc)
    Doc_pro_test = np.array(Doc_pro_test)
    print(Doc_pro_test)
    stop = 0  # 迭代停止标志
    loopcount = 1  # 迭代次数
    while stop == 0:
        i = 0
        for data in test_txt:
            top = Topic_All_test[i]
            for w in range(len(data)):
                word = data[w]
                pro = []
                topfre = []
                if '\u4e00' <= word <= '\u9fa5':
                    for j in range(len(data_txt)):
                        exec('topfre.append(Topic_fre{}.get(word, 0))'.format(j))  # 读取该词语在每个topic中出现的频数
                    pro = Doc_pro_test[i] * topfre / Topic_count  # 计算每篇文章选中各个topic的概率乘以该词语在每个topic中出现的概率,得到该词出现的概率向量
                    m = np.argmax(pro)  # 认为该词是由上述概率之积最大的那个topic产生的
                    Doc_fre_test[i][top[w]] -= 1  # 更新每个文档有多少各个topic的词
                    Doc_fre_test[i][m] += 1
                    top[w] = m
            Topic_All_test[i] = top
            i += 1
        print(Doc_fre_test, 'new')
        if loopcount == 1:  # 计算新的每篇文章选中各个topic的概率
            for i in range(len(test_txt)):
                doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
                Doc_pronew_test.append(doc)
            Doc_pronew_test = np.array(Doc_pronew_test)
        else:
            for i in range(len(test_txt)):
                doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
                Doc_pronew_test[i] = doc
        print(Doc_pro_test)
        print(Doc_pronew_test)
        if (Doc_pronew_test == Doc_pro_test).all():  # 如果每篇文章选中各个topic的概率不再变化,则认为训练集已分类完毕
            stop = 1
        else:
            Doc_pro_test = Doc_pronew_test.copy()
        loopcount += 1
    print(Doc_pronew)
    print(Doc_pronew_test)
    print(loopcount)
    print('测试集测试完毕!')
    result = []
    for k in range(len(test_txt)):
        pro = []
        for i in range(len(data_txt)):
            dis = 0
            for j in range(len(data_txt)):
                dis += (Doc_pro[i][j] - Doc_pro_test[k][j])**2  # 计算欧式距离
            pro.append(dis)
        m = pro.index(min(pro))
        print(pro)
        result.append(m)
    print(files)
    print(result)

以上代码参考前辈代码,与前人代码相比,本人代码新增段落处理模块,针对作业给出段落要求,对段落进行分割

https://blog.csdn.net/shzx_55733/article/details/116280982?spm=1001.2014.3001.5501


四、实验总结

1、实验结果

本次应用了LDA模型对语料进行了模型训练与测试,从实验结果看出:

  • 在模型训练阶段,经过15次迭代(见下图),得到最终构建的LDA模型
    在这里插入图片描述

-最终测试集的(部分)结果如下所示:每一篇对应的顺序与在该文章在语料库内摆放的顺序一致。
在这里插入图片描述
其他实验txt结果及相关代码见网盘NLP-3所示。

2、实验分析

本次实验通过构建LDA模型,来对金庸小说集主题进行分类,测试效果非常好。
通过这次作业,加深了我对自然语言处理用途的理解,但本次任务仍存在不足之处,本次代码的运行时间较长,在未来,可以考虑对Topic进行精炼,选取重要的关键词进行处理,这将明显降低运行的时间。

附录

实验txt结果及相关代码见网盘NLP-3所示。
本次实验的完整代码如下所示,实验代码使用python实现:

import math
import jieba
import os  # 用于处理文件路径
import random
import numpy as np
def read_novel(path):  # 读取语料内容
    content = []
    names = os.listdir(path)
    for name in names:
            con_temp = []
            novel_name = path + '\\' + name
            with open(novel_name, 'r', encoding='ANSI') as f:
                con = f.read()
                con = content_deal(con)
                con = jieba.lcut(con)  # 结巴分词
                con_list = list(con)
                pos = int(len(con)//13) ####16篇文章,分词后,每篇均匀选取13个500词段落进行建模
                for i in range(13):
                    con_temp = con_temp + con_list[i*pos:i*pos+500]
                content.append(con_temp)
            f.close()
    return content, names


def read_novel1(path):  # 读取语料内容
    content = []
    names = os.listdir(path)
    for name in names:
            con_temp = []
            novel_name = path + '\\' + name
            with open(novel_name, 'r', encoding='ANSI') as f:
                con = f.read()
                con = content_deal(con)
                con = jieba.lcut(con)  # 结巴分词
                con_list = list(con)
                pos = int(len(con)//13) ####16篇文章,分词后,每篇均匀选取13个500词段落进行建模
                for i in range(13):
                    con_temp = con_temp + con_list[i*pos+501:i*pos+1000]
                content.append(con_temp)
            f.close()
    return content, names



def content_deal(content):  # 语料预处理,进行断句,去除一些广告和无意义内容
    ad = ['本书来自www.cr173.com免费txt小说下载站\n更多更新免费电子书请关注www.cr173.com', '----〖新语丝电子文库(www.xys.org)〗', '新语丝电子文库',
          '\u3000', '\n', '。', '?', '!', ',', ';', ':', '、', '《', '》', '“', '”', '‘', '’', '[', ']', '....', '......',
          '『', '』', '(', ')', '…', '「', '」', '\ue41b', '<', '>', '+', '\x1a', '\ue42b']
    for a in ad:
        content = content.replace(a, '')
    return content


if __name__ == '__main__':
    [data_txt, files] = read_novel("金庸小说集")
    Topic_All = []  # 每篇文章中的每个词来自哪个topic
    Topic_count = {}  # 每个topic有多少词
    Topic_fre0 = {}; Topic_fre1 = {}; Topic_fre2 = {}; Topic_fre3 = {};
    Topic_fre4 = {}; Topic_fre5 = {}; Topic_fre6 = {}; Topic_fre7 = {};
    Topic_fre8 = {}; Topic_fre9 = {}; Topic_fre10 = {}; Topic_fre11 = {};
    Topic_fre12 = {}; Topic_fre13 = {}; Topic_fre14 = {}; Topic_fre15 = {}  # 每个topic的词频
    Doc_count = []  # 每篇文章中有多少个词
    Doc_fre = []  # 每篇文章有多少各个topic的词
    i = 0
    for data in data_txt:
        topic = []
        docfre = {}
        for word in data:
            a = random.randint(0, len(data_txt)-1)  # 为每个单词赋予一个随机初始topic
            topic.append(a)
            if '\u4e00' <= word <= '\u9fa5':
                Topic_count[a] = Topic_count.get(a, 0) + 1  # 统计每个topic总词数
                docfre[a] = docfre.get(a, 0) + 1  # 统计每篇文章的词频
                exec('Topic_fre{}[word]=Topic_fre{}.get(word, 0) + 1'.format(i, i))  # 统计每个topic的词频
        Topic_All.append(topic)
        docfre = list(dict(sorted(docfre.items(), key=lambda x: x[0], reverse=False)).values())
        Doc_fre.append(docfre)
        Doc_count.append(sum(docfre))  # 统计每篇文章的总词数
        # exec('print(len(Topic_fre{}))'.format(i))
        i += 1
    Topic_count = list(dict(sorted(Topic_count.items(), key=lambda x: x[0], reverse=False)).values())
    # print(Topic_All[0])
    Doc_fre = np.array(Doc_fre)  # 转为array方便后续计算
    Topic_count = np.array(Topic_count)  # 转为array方便后续计算
    Doc_count = np.array(Doc_count)  # 转为array方便后续计算
    print(Doc_fre)
    print(Topic_count)
    print(Doc_count)
    # print(Topic_fre0)
    Doc_pro = []  # 每个topic被选中的概率
    Doc_pronew = []  # 记录每次迭代后每个topic被选中的新概率
    for i in range(len(data_txt)):
        doc = np.divide(Doc_fre[i], Doc_count[i])
        Doc_pro.append(doc)
    Doc_pro = np.array(Doc_pro)
    print(Doc_pro)
    stop = 0  # 迭代停止标志
    loopcount = 1  # 迭代次数
    while stop == 0:
        i = 0
        for data in data_txt:
            top = Topic_All[i]
            for w in range(len(data)):
                word = data[w]
                pro = []
                topfre = []
                if '\u4e00' <= word <= '\u9fa5':
                    for j in range(len(data_txt)):
                        exec('topfre.append(Topic_fre{}.get(word, 0))'.format(j))  # 读取该词语在每个topic中出现的频数
                    pro = Doc_pro[i] * topfre / Topic_count  # 计算每篇文章选中各个topic的概率乘以该词语在每个topic中出现的概率,得到该词出现的概率向量
                    m = np.argmax(pro)  # 认为该词是由上述概率之积最大的那个topic产生的
                    Doc_fre[i][top[w]] -= 1  # 更新每个文档有多少各个topic的词
                    Doc_fre[i][m] += 1
                    Topic_count[top[w]] -= 1  # 更新每个topic的总词数
                    Topic_count[m] += 1
                    exec('Topic_fre{}[word] = Topic_fre{}.get(word, 0) - 1'.format(top[w], top[w]))  # 更新每个topic该词的频数
                    exec('Topic_fre{}[word] = Topic_fre{}.get(word, 0) + 1'.format(m, m))
                    top[w] = m
            Topic_All[i] = top
            i += 1
        print(Doc_fre, 'new')
        print(Topic_count, 'new')
        if loopcount == 1:  # 计算新的每篇文章选中各个topic的概率
            for i in range(len(data_txt)):
                doc = np.divide(Doc_fre[i], Doc_count[i])
                Doc_pronew.append(doc)
            Doc_pronew = np.array(Doc_pronew)
        else:
            for i in range(len(data_txt)):
                doc = np.divide(Doc_fre[i], Doc_count[i])
                Doc_pronew[i] = doc
        print(Doc_pro)
        print(Doc_pronew)
        if (Doc_pronew == Doc_pro).all():  # 如果每篇文章选中各个topic的概率不再变化,则认为模型已经训练完毕
            stop = 1
        else:
            Doc_pro = Doc_pronew.copy()
        loopcount += 1
    print(Doc_pronew)  # 输出最终训练的到的每篇文章选中各个topic的概率
    print(loopcount)  # 输出迭代次数
    # print(Doc_pro0)
    # print(Doc_pronew0)
    print('模型训练完毕!')

    [test_txt, files] = read_novel1("金庸小说集")
    Doc_count_test = []  # 每篇文章中有多少个词
    Doc_fre_test = []  # 每篇文章有多少各个topic的词
    Topic_All_test = []  # 每篇文章中的每个词来自哪个topic
    i = 0
    for data in test_txt:
        topic = []
        docfre = {}
        for word in data:
            a = random.randint(0, len(data_txt) - 1)  # 为每个单词赋予一个随机初始topic
            topic.append(a)
            if '\u4e00' <= word <= '\u9fa5':
                docfre[a] = docfre.get(a, 0) + 1  # 统计每篇文章的词频
        Topic_All_test.append(topic)
        docfre = list(dict(sorted(docfre.items(), key=lambda x: x[0], reverse=False)).values())
        Doc_fre_test.append(docfre)
        Doc_count_test.append(sum(docfre))  # 统计每篇文章的总词数
        i += 1
    # print(Topic_All[0])
    Doc_fre_test = np.array(Doc_fre_test)
    Doc_count_test = np.array(Doc_count_test)
    print(Doc_fre_test)
    print(Doc_count_test)
    Doc_pro_test = []  # 每个topic被选中的概率
    Doc_pronew_test = []  # 记录每次迭代后每个topic被选中的新概率
    for i in range(len(test_txt)):
        doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
        Doc_pro_test.append(doc)
    Doc_pro_test = np.array(Doc_pro_test)
    print(Doc_pro_test)
    stop = 0  # 迭代停止标志
    loopcount = 1  # 迭代次数
    while stop == 0:
        i = 0
        for data in test_txt:
            top = Topic_All_test[i]
            for w in range(len(data)):
                word = data[w]
                pro = []
                topfre = []
                if '\u4e00' <= word <= '\u9fa5':
                    for j in range(len(data_txt)):
                        exec('topfre.append(Topic_fre{}.get(word, 0))'.format(j))  # 读取该词语在每个topic中出现的频数
                    pro = Doc_pro_test[i] * topfre / Topic_count  # 计算每篇文章选中各个topic的概率乘以该词语在每个topic中出现的概率,得到该词出现的概率向量
                    m = np.argmax(pro)  # 认为该词是由上述概率之积最大的那个topic产生的
                    Doc_fre_test[i][top[w]] -= 1  # 更新每个文档有多少各个topic的词
                    Doc_fre_test[i][m] += 1
                    top[w] = m
            Topic_All_test[i] = top
            i += 1
        print(Doc_fre_test, 'new')
        if loopcount == 1:  # 计算新的每篇文章选中各个topic的概率
            for i in range(len(test_txt)):
                doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
                Doc_pronew_test.append(doc)
            Doc_pronew_test = np.array(Doc_pronew_test)
        else:
            for i in range(len(test_txt)):
                doc = np.divide(Doc_fre_test[i], Doc_count_test[i])
                Doc_pronew_test[i] = doc
        print(Doc_pro_test)
        print(Doc_pronew_test)
        if (Doc_pronew_test == Doc_pro_test).all():  # 如果每篇文章选中各个topic的概率不再变化,则认为训练集已分类完毕
            stop = 1
        else:
            Doc_pro_test = Doc_pronew_test.copy()
        loopcount += 1
    print(Doc_pronew)
    print(Doc_pronew_test)
    print(loopcount)
    print('测试集测试完毕!')
    result = []
    for k in range(len(test_txt)):
        pro = []
        for i in range(len(data_txt)):
            dis = 0
            for j in range(len(data_txt)):
                dis += (Doc_pro[i][j] - Doc_pro_test[k][j])**2  # 计算欧式距离
            pro.append(dis)
        m = pro.index(min(pro))
        print(pro)
        result.append(m)
    print(files)
    print(result)

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐