# 说明
# - 依赖库:tarfile、os、jieba、gensim、bs4
# - 程序输入:article.txt、news_data.tar.gz
# - 程序输出:打印输出18个主题及新文本的预测主题归属
# 程序
# 导入库
import os
import tarfile
import jieba.posseg as pseg
from bs4 import BeautifulSoup
from gensim import corpora, models
# 函数模块
# 中文分词
def jieba_cut(text):
'''
将输入的文本句子根据词性标注做分词
:param text: 文本句子,字符串型
:return: 符合规则的分词结果
'''
rule_words = ['z', 'vn', 'v', 't', 'nz', 'nr', 'ns', 'n', 'l', 'i', 'j', 'an', 'a']
words = pseg.cut(text)
seg_list = [word.word for word in words if word.flag in rule_words]
return seg_list
# 文本预处理
def text_pro(words_list, tfidf_object=None, training=True):
'''
gensim主题建模预处理过程,包含分词类别转字典、生成语料库和TF-IDF转换
:param words_list: 分词列表,列表型
:param tfidf_object: TF-IDF模型对象,该对象在训练阶段生成
:param training: 是否训练阶段,用来针对训练和预测两个阶段做预处理
:return: 如果是训练阶段,返回词典、TF-IDF对象和TF-IDF向量空间数据;如果是预测阶段,返回TF-IDF向量空间数据
'''
# 分词列表转字典
dic = corpora.Dictionary(words_list) # 将分词列表转换为字典形式
print('{:*^60}'.format('token & word mapping review:'))
for i, w in list(dic.items())[:5]: # 循环读出字典前5条的每个key和value,对应的是索引值和分词
print('token:%s -- word:%s' % (i, w))
# 生成语料库
corpus = [dic.doc2bow(words) for words in words_list] # 用于存储语料库的列表
print('{:*^60}'.format('bag of words review:'))
print(corpus[0])
# TF-IDF转换
if training:
tfidf = models.TfidfModel(corpus) # 建立TF-IDF模型对象
corpus_tfidf = tfidf[corpus] # 得到TF-IDF向量稀疏矩阵
print('{:*^60}'.format('TF-IDF model review:'))
print(list(corpus_tfidf)[0]) # 打印第一条向量
return dic, corpus_tfidf, tfidf
else:
return tfidf_object[corpus]
# 全角转半角
def str_convert(content):
'''
将内容中的全角字符,包含英文字母、数字键、符号等转换为半角字符
:param content: 要转换的字符串内容
:return: 转换后的半角字符串
'''
strs = []
for each_char in content: # 循环读取每个字符
code_num = ord(each_char) # 读取字符的ASCII值或Unicode值
if code_num == 12288: # 全角空格直接转换
code_num = 32
elif 65281 <= code_num <= 65374: # 全角字符(除空格)根据关系转化
code_num -= 65248
strs.append(chr(code_num))
return ''.join(strs)
# 解析文件内容
def data_parse(data):
'''
从原始文件中解析出文本内容数据
:param data: 包含代码的原始内容
:return: 文本中的所有内容,列表型
'''
raw_code = BeautifulSoup(data, 'lxml') # 建立BeautifulSoup对象
content_code = raw_code.find_all('content') # 从包含文本的代码块中找到content标签
content_list = [str_convert(each_content.text) for each_content in content_code if len(each_content) > 0]
return content_list
# 读取数据并解析
# 解压缩文件
if not os.path.exists('./news_data'): # 如果不存在数据目录,则先解压数据文件
with tarfile.open('news_data.tar.gz') as tar: # 打开tar.gz压缩包对象
names = tar.getnames() # 获得压缩包内的每个文件对象的名称
for name in names: # 循环读出每个文件
tar.extract(name, path='./') # 将文件解压到指定目录
# 汇总所有内容
all_content = [] # 总列表,用于存储所有文件的文本内容
for root, dirs, files in os.walk('./news_data'): # 分别读取遍历目录下的根目录、子目录和文件列表
for file in files: # 读取每个文件
file_name = os.path.join(root, file) # 将目录路径与文件名合并为带有完整路径的文件名
with open(file_name, encoding='utf-8') as f: # 以只读方式打开文件
data = f.read() # 读取文件内容
all_content.extend(data_parse(data)) # 从文件内容中获取文本并将结果追加到总列表
# 分词
print('get word list...')
words_list = [list(jieba_cut(each_content)) for each_content in all_content] # 分词列表,用于存储所有文件的分词结果
# 建立主题模型
dic, corpus_tfidf, tfidf = text_pro(words_list) # 训练集的文本预处理
num_topics = 3 # 设置主题个数
lda = models.LdaModel(corpus_tfidf, id2word=dic, num_topics=num_topics) # 通过LDA进行主题建模
print('{:*^60}'.format('topic model review:'))
print(lda.print_topics())
# 新数据集的主题模型预测
with open('article.txt', encoding='utf-8') as f: # 打开新的文本
text_new = f.read() # 读取文本数据
text_content = data_parse(data) # 解析新的文本
words_list_new = jieba_cut(text_new) # 将文本转换为分词列表
corpus_tfidf_new = text_pro([words_list_new], tfidf_object=tfidf, training=False) # 新文本数据集的预处理
corpus_lda_new = lda[corpus_tfidf_new] # 获取新的分词列表(文档)的主题概率分布
print('{:*^60}'.format('topic forecast:'))
print(list(corpus_lda_new))
注:数据文件链接: https://pan.baidu.com/s/1LN0ZVjf-WfgUFLEXf4VXIA 密码: 0qg4