问题提出
在给定的数据库上利用Topic Model做无监督学习,学习到主题的分布。可以在数据库中随机选定K本小说,在每本小说中随机抽出M个段落作为训练数据,并抽出N个段落作为测试,利用topic model和其他的分类器对给定的段落属于哪一本小说进行分类。 其中K至少为3.
一、Topic Model
Topic model 是一种统计建模,用于发现出现在文档集合中的抽象主题。潜在 Dirichlet 分配(Latent Dirichlet Allocation, LDA)是Topic model的一种,用于将文档中的文本分类为特定的主题。本文就采用了LDA模型对语料进行学习与分类。
二、LDA模型
1.LDA概述
LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,也称为一个三层贝叶斯概率模型,包含词、主题和文档三层结构。所谓生成模型,就是说,我们认为一篇文章的每个词都是通过“以一定概率选择了某个主题,并从这个主题中以一定概率选择某个词语”这样一个过程得到。文档到主题服从多项式分布,主题到词服从多项式分布。
LDA是一种非监督机器学习技术,可以用来识别大规模文档集(document collection)或语料库(corpus)中潜藏的主题信息。它采用了词袋(bag of words)的方法,这种方法将每一篇文档视为一个词频向量,从而将文本信息转化为了易于建模的数字信息。但是词袋方法没有考虑词与词之间的顺序,这简化了问题的复杂性,同时也为模型的改进提供了契机。每一篇文档代表了一些主题所构成的一个概率分布,而每一个主题又代表了很多单词所构成的一个概率分布。
2.LDA生成过程
首先定义文档集合
D
D
D,主题(topic)集合
T
T
T
D
D
D中每个文档
d
d
d看作一个单词序列
<
w
1
,
w
2
,
.
.
.
,
w
n
>
<w1,w2,...,wn>
<w1,w2,...,wn>,
w
i
wi
wi表示第
i
i
i个单词,设
d
d
d有
n
n
n个单词。
D
D
D中涉及的所有不同单词组成一个大集合VOC,LDA以文档集合
D
D
D作为输入,希望训练出的两个结果向量(设聚成
k
k
k个Topic,VOC中共包含
m
m
m个词):
·对每个
D
D
D中的文档
d
d
d,对应到不同Topic的概率
θ
d
<
p
t
1
,
.
.
.
,
p
t
k
>
θd<pt1,...,ptk>
θd<pt1,...,ptk>,其中,
p
t
i
pti
pti表示
d
d
d对应
T
T
T中第
i
i
i个Topic的概率。计算方法是直观的,
p
t
i
=
n
t
i
/
n
pti=nti/n
pti=nti/n,其中
n
t
i
nti
nti表示
d
d
d中对应第
i
i
i个Topic的词的数目,
n
n
n是
d
d
d中所有词的总数。
·对每个
T
T
T中的Topic,生成不同单词的概率
φ
t
<
p
w
1
,
.
.
.
,
p
w
m
>
φt<pw1,...,pwm>
φt<pw1,...,pwm>,其中,
p
w
i
pwi
pwi表示
t
t
t生成VOC中第
i
i
i个单词的概率。计算方法同样很直观,
p
w
i
=
N
w
i
/
N
pwi=Nwi/N
pwi=Nwi/N,其中
N
w
i
Nwi
Nwi表示对应到Topic的VOC中第
i
i
i个单词的数目,N表示所有对应到Topic的单词总数。
LDA的核心公式如下:
p
(
w
∣
d
)
=
p
(
w
∣
t
)
∗
p
(
t
∣
d
)
p(w|d)=p(w|t)*p(t|d)
p(w∣d)=p(w∣t)∗p(t∣d)
直观的看这个公式,就是以Topic作为中间层,可以通过当前的
θ
d
θd
θd和
φ
t
φt
φt给出了文档
d
d
d中出现单词
w
w
w的概率。其中
p
(
t
∣
d
)
p(t|d)
p(t∣d)利用θd计算得到,
p
(
w
∣
t
)
p(w|t)
p(w∣t)利用
φ
t
φt
φt计算得到。利用当前的
θ
d
θd
θd和
φ
t
φt
φt,我们可以为一个文档中的一个单词计算它对应任意一个Topic时的
p
(
w
∣
d
)
p(w|d)
p(w∣d),然后根据这些结果来更新这个词应该对应的Topic。然后,如果这个更新改变了这个单词所对应的Topic,就会反过来影响
θ
d
θd
θd和
φ
t
φt
φt。
三、实验过程
1.预处理
代码如下:
def read_novel(path): # 读取语料内容
content = []
names = os.listdir(path)
for name in names:
novel_name = path + '\\' + name
with open(novel_name, 'r', encoding='ANSI') as f:
con = f.read()
con = content_deal(con) # 语料预处理
con = jieba.lcut(con) # 结巴分词
content.append(con)
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_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.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方便后续计算
3.模型训练
首先计算每个topic被选中的概率:
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)
然后进行迭代,训练模型,具体步骤参加注释,已十分详细:
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('模型训练完毕!')
本次训练使用了白马啸西风、碧血剑、飞狐外传三本小说作为语料库,训练的到的每本小说分属各个Topic的概率如下:
Topic1 | Topic2 | Topic3 |
---|---|---|
0.24274857 | 0.44900515 | 0.30824628 |
0.00396827 | 0.72040228 | 0.27562945 |
0.00528300 | 0.37310383 | 0.62161317 |
4.数据测试
在三本小说中分别节选了5个部分作为测试数据集,即最终形成了15篇待分类文章。
首先仍然在读取后对15篇待分类文章进行预处理,之后将15篇待分类文章中的每个词赋予一个随机的初始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)
在完成这些后,同样通过迭代,但迭代中计算概率时,每个词在每个Topic中出现的概率时固定的,每个Topic有多少词也是固定的,即我们的 K K K个Topic的骰子已经固定:
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('测试集测试完毕!')
迭代完成后,得到的每篇测试文章分别属于各个Topic的概率如下:
序号 | Topic1 | Topic2 | Topic3 |
---|---|---|---|
1 | 0.21046512 | 0.39883721 | 0.39069767 |
2 | 0.24908425 | 0.50549451 | 0.24542125 |
3 | 0.23011016 | 0.44920441 | 0.32068543 |
4 | 0.22222222 | 0.40185185 | 0.37592593 |
5 | 0.29087328 | 0.50295469 | 0.20617203 |
6 | 0.00406268 | 0.66569936 | 0.33023796 |
7 | 0.00684396 | 0.74208056 | 0.25107548 |
8 | 0.00252568 | 0.68277488 | 0.31469944 |
9 | 0.00354167 | 0.71895833 | 0.2775000 |
10 | 0.0030303 | 0.84199134 | 0.15497835 |
11 | 0.00799087 | 0.39840183 | 0.59360731 |
12 | 0.00189544 | 0.36281788 | 0.63528668 |
13 | 0.00223547 | 0.34053651 | 0.65722802 |
14 | 0.00115585 | 0.39163938 | 0.60720478 |
15 | 0.00419964 | 0.34420934 | 0.65159102 |
接下来,则需要根据这些概率结果,区分每篇待分类文章究竟来自哪一本小说,此处我采用的是欧式距离的方式,即比较待分类文章与已知的小说,两者对于各个Topic的概率向量之间的距离最近,即认为是来自该本小说,欧式距离的计算过程如下:
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)
最终得到的欧式距离如下:
序号 | 白马啸西风 | 碧血剑 | 飞狐外传 |
---|---|---|---|
1 | 0.010357276585702542 | 0.15928574139581006 | 0.09608387544877363 |
2 | 0.007178172621532558 | 0.10717973142389543 | 0.2184867066907407 |
3 | 0.0003145017322052663 | 0.12671848444084058 | 0.1468960532992692 |
4 | 0.007225299380972274 | 0.1591685487851313 | 0.1082512986030865 |
5 | 0.015645692918783576 | 0.13442226916573932 | 0.2710143976392976 |
6 | 0.10441096759923334 | 0.005974508025499254 | 0.17051315054588634 |
7 | 0.14481268272037973 | 0.0010811146933760937 | 0.27344444857253625 |
8 | 0.11239696584517603 | 0.00294436747093477 | 0.19009979736829433 |
9 | 0.13103999608770062 | 5.765953987083401e-06 | 0.23803224531248673 |
10 | 0.23539404904965106 | 0.029341464767399135 | 0.4376086266135305 |
11 | 0.139102791385722 | 0.2048103948180074 | 0.0014316497501364188 |
12 | 0.17239390560830656 | 0.2572242311092172 | 0.00030424127748361716 |
13 | 0.1914002517350596 | 0.28991847627600364 | 0.0023383347939665523 |
14 | 0.15103406038239398 | 0.21803515943185114 | 0.0005682016960899776 |
15 | 0.18577336384553167 | 0.28286829148814124 | 0.0017347367165797397 |
最终根据欧式距离最短,得到最终的分类结果为1-5为白马啸西风、6-10为碧血剑、11-15为飞狐外传,与实际情况完全吻合,正确率100%。
之所以这么按照顺序来则是与我在测试集中拜访这些文章的顺序有关,测试集文件夹如图所示,修改摆放顺序同样能够100%判断正确。
程序中的输出截图如下:
总结
本次应用Topic Model中的一例,即LDA模型对语料进行了模型训练与测试,测试效果非常好,通过实践也加深了我对自然语言处理的认识和理解,但本次任务完成仍然存在不足之处,例如代码的复杂度有些高,在我已经进行简化后仍然需要220s左右的时间才能完成全部过程,而随着语料库的增加整体时间则会拉得更长,后续我将继续优化算法,例如每篇文章、每个Topic应该只选取重点的词来处理,而不是全部,这将显著降低算法的时间复杂度。
附录
所有代码如下:
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:
novel_name = path + '\\' + name
with open(novel_name, 'r', encoding='ANSI') as f:
con = f.read()
con = content_deal(con)
con = jieba.lcut(con) # 结巴分词
content.append(con)
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("../深度学习与自然语言处理/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_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)