本文目的
搜索关键词,返回最相关的txt文本内容(模仿搜索引擎)
网上的例子都是一个list里面放入几句话,然后输入关键词去计算相似度.
无法在实际中应用,例如
http://blog.csdn.net/appleyuchi/article/details/78062721
下面改进了下,
下面改为输入一句话,不是去list中查找,而是去文件夹中查找,这样就有一个搜索引擎的雏形
下面代码在python2.7,linux下运行,运行时,修改path以及question即可
path代表存放一大堆txt文件的文件夹的路径
下面代码实现question与这些txt文件做相似度计算的功能.
运行环境
组件 | 版本 |
Ubuntu | 18.10 |
python | 2.7.12 |
运行方法
①mkdir train
②mkdir train_corpus_seg
③解压tc-corpus-train.zip到train文件夹中
注:
解压后会有一大堆文件夹,为了运行调试方便的目的,可以删除其余文件夹,只留两个文件夹即可,
每个文件夹表示一个大类。
④python corpus_segment.py
⑤python top.py
数据集采用复旦大学的新闻数据集tc-corpus-train.zip
下载链接是:
链接: https://pan.baidu.com/s/1hAxkar56UM6U_Eo8vm0rOA 密码: mpqd
实验大意
附录代码中设置搜索关键词question:“邹家华 矿产”(模仿搜索引擎中输入关键词)
返回与关键词最相关的一篇文章内容。(模仿搜索引擎返回最相关的网页)
附录代码中有三个模型,每个模型都返回了最匹配的文章的序号。
第一个模型额外增加代码get_article,返回了"最匹配的文章的序号"对应的"具体的内容"
其他两个模型仅仅返回最相关的文章的序号,不返回内容(若要返回文章内容可以模仿第一个模型的例子来添加)
实验运行结果
-------------------下面是tfidf模型(第1个提问)----------------------------------------------------
Building prefix dict from the default dictionary ...
Loading model from cache /tmp/jieba.cache
Loading model cost 0.545 seconds.
Prefix dict has been built succesfully.
[(1, 0.3586881756782532), (18, 0.28805285692214966), (15, 0.2172296941280365), (13, 0.20284029841423035), (21, 0.06617657840251923)]
搜索得到最匹配的文章是: 【 日期 】 19960404 【 版号 】 2 【 标题 】 全国 矿产资源 委员会 成立 邹家华 提出 全面 加强 矿产 资源管理 【 作者 】 朱幼棣 【 正文 】 据 新华社 北京 4 月 3 日电 ( 记者 朱幼棣 ) 全国 矿产资源 委员会 第一次 会议 今天 召开 , 国务院 副 总理 、 全国 资源委 主任 邹家华 说 , 国务院 决定 成立 全国 矿产资源 委员会 , 取代 原来 的 全国 矿产 储量 委员会 , 这是 国务院 为了 全面 加强 矿产 资源管理 的 一项 重要 措施 , 是 我国 矿产 资源管理 体制 上 的 一项 重要 改革 。 邹家华 说 , 国务院 十分重视 作为 国民经济 发展 的 基础产业 矿产资源 工作 。 我国 矿产 资源管理 体制 , 随着 国家 经济 的 发展 和 历史 演变 , 发生 了 许多 变化 , 总的来说 也 是 不断 适应 生产力 的 发展 , 也 因此 大大 推进 了 国民经济 的 发展 。 但 从 当前 实践 中看 , 矿产 资源管理 体制 不能 进一步 适应 生产力 发展 的 需要 , 没有 能够 按照 宪法 的 要求 , 真正 体现 中央政府 的 集中 、 统一 和 有效 的 管理 , 不能 在 维护 矿产资源 国家所有 的 权益 , 合理 规划 利用 资源 , 加强 政策 调控 等 方面 发挥 应有 的 作用 , 还 存在 着 多头管理 、 地方 保护 和 部门 分割 的 状况 。 为此 , 从 我国 国情 出发 , 需要 一个 高层次 的 议事 协调 机构 , 不仅 是 对 全国 矿产 储量 的 确认 , 而且 是 在 全国 范围 内 , 统筹 矿产资源 勘查 、 开发 、 利用 、 保护 与 管理 方面 的 政策 和 方针 , 协调 各 部门 和 各大 公司 的 工作 , 共同努力 办 一些 大事 、 实事 , 解决 一些 重大 问题 。 邹家华 说 , 党 的 十四届 五中全会 《 建议 》 和 八届 人大 四次会议 批准 的 《 纲要 》 , 对 加强 自然资源 保护 、 环境 、 生态 保护 也 提出 了 目标 、 工作 重点 和 政策措施 。 这 充分 显示 了 党中央 、 国务院 对 资源管理 工作 的 高度 关心 、 重视 和 支持 , 也 表明 了 资源管理 工作 责任 更 重大 、 任务 更 艰巨 。 对 今后 矿产资源 保护 管理 的 重要性 与 紧迫性 , 各 部门 、 各级 地方 政府 都 要 从 战略 高度 深刻 认识 。 全国 矿产资源 委员会 的 主要 任务 是 研究 矿产资源 政策 , 酝酿 一个 时期 内 资源 开发 与 保护 的 行动计划 和 重大项目 , 协调 各 部门 和 地方 的 关系 。 矿产资源 委员会 要 承担 起 维护 矿产资源 国家所有 、 促进 矿产资源 的 开发 与 保护 、 实现 可 持续 发展 的 历史使命 。 邹家华 提出 , 今后 资源 委员会 要 紧紧围绕 《 建议 》 和 《 纲要 》 的 目标 , 开拓 新 体制 、 探索 新 政策 、 制定 新 战略 , 做好 工作 , 一是 促进 资源管理 新 体制 的 建立 , 建设 统一 、 协调 、 高效 、 权威 的 中央 统一 管理 与 授权 地方 管理 相结合 的 资源管理 体系 ; 二是 促进 地质 勘查 和 矿业 的 健康 发展 , 为 国民经济 与 社会 发展 提供 必要 的 资源 保障 , 努力 达到 资源 供需平衡 ; 三是 通过 实施 可 持续 发展 战略 与 科教兴国 战略 , 最大 限度 地 合理 开发利用 矿产资源 , 提高 资源 的 综合利用 水平 , 保护 生态环境 ; 四是 促进 矿产资源 法制建设 , 推动 矿产资源 开发 与 管理 的 整体 水平 上 一个 新台阶 。 国务院 副 秘书长 周正庆 宣读 了 《 国务院办公厅 关于 将 全国 矿产 储量 委员会 更名 为 全国 矿产资源 委员会 及 组成 人员 的 通知 》 。
-------------------下面是tfidf模型(第2个提问)----------------------------------------------------
[(1, 0.3586881756782532), (18, 0.28805285692214966), (15, 0.2172296941280365)]
-------------------下面是LSI模型-----------------------------------
[(1, 0.948716402053833), (13, 0.8921045064926147)]
参考文献
Reference:
[1]https://blog.csdn.net/github_36326955/article/details/54891204
[2]https://blog.csdn.net/u011630575/article/details/80159298
附录
corpus_segment.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@version: python2.7.8
@author: XiangguoSun
@contact: sunxiangguodut@qq.com
@file: corpus_segment.py
@time: 2017/2/5 15:28
@software: PyCharm
"""
import sys
import os
import jieba
# 配置utf-8输出环境
reload(sys)
sys.setdefaultencoding('utf-8')
# 保存至文件
def savefile(savepath, content):
with open(savepath, "wb") as fp:
fp.write(content)
'''''
上面两行是python2.6以上版本增加的语法,省略了繁琐的文件close和try操作
2.5版本需要from __future__ import with_statement
新手可以参考这个链接来学习http://zhoutall.com/archives/325
'''
# 读取文件
def readfile(path):
with open(path, "rb") as fp:
content = fp.read()
return content
def corpus_segment(corpus_path, seg_path):
'''''
corpus_path是未分词语料库路径
seg_path是分词后语料库存储路径
'''
catelist = os.listdir(corpus_path) # 获取corpus_path下的所有子目录
'''''
其中子目录的名字就是类别名,例如:
train_corpus/art/21.txt中,'train_corpus/'是corpus_path,'art'是catelist中的一个成员
'''
# 获取每个目录(类别)下所有的文件
for mydir in catelist:
'''''
这里mydir就是train_corpus/art/21.txt中的art(即catelist中的一个类别)
'''
class_path = corpus_path + mydir + "/" # 拼出分类子目录的路径如:train_corpus/art/
seg_dir = seg_path + mydir + "/" # 拼出分词后存贮的对应目录路径如:train_corpus_seg/art/
if not os.path.exists(seg_dir): # 是否存在分词目录,如果没有则创建该目录
os.makedirs(seg_dir)
file_list = os.listdir(class_path) # 获取未分词语料库中某一类别中的所有文本
'''''
train_corpus/art/中的
21.txt,
22.txt,
23.txt
...
file_list=['21.txt','22.txt',...]
'''
for file_path in file_list: # 遍历类别目录下的所有文件
fullname = class_path + file_path # 拼出文件名全路径如:train_corpus/art/21.txt
content = readfile(fullname) # 读取文件内容
'''''此时,content里面存贮的是原文本的所有字符,例如多余的空格、空行、回车等等,
接下来,我们需要把这些无关痛痒的字符统统去掉,变成只有标点符号做间隔的紧凑的文本内容
'''
content = content.replace("\r\n", "") # 删除换行
content = content.replace(" ", "")#删除空行、多余的空格
content_seg = jieba.cut(content) # 为文件内容分词
savefile(seg_dir + file_path, " ".join(content_seg)) # 将处理后的文件保存到分词后语料目录
print "中文语料分词结束!!!"
if __name__=="__main__":
#对训练集进行分词
corpus_path = "./train/" # 未分词分类语料库路径
seg_path = "./train_corpus_seg/" # 分词后分类语料库路径,本程序输出结果
corpus_segment(corpus_path,seg_path)
# #对测试集进行分词
# corpus_path = "/home/appleyuchi/PycharmProjects/MultiNB/csdn_blog/54891204_tenwhy/chinese_text_classification-master/answer/" # 未分词分类语料库路径
# seg_path = "/home/appleyuchi/PycharmProjects/MultiNB/csdn_blog/54891204_tenwhy/chinese_text_classification-master/test_corpus_seg/" # 分词后分类语料库路径,本程序输出结果
# corpus_segment(corpus_path,seg_path)
top.py
# #-*- coding:utf-8 -*-
# import sys
# reload(sys)
# sys.setdefaultencoding("utf-8")
import os
from gensim import corpora,models,similarities
folders="./train_corpus_seg/"
path="files/"
import jieba
#这个其实相当于搜索引擎(实际中是爬虫)
# 得到的各大网站的网页内容存储到一个个文件夹里面,
# 当用户搜索的时候,从文件夹里面搜索最相关文章匹配的链接返回给用户
file_list=[]
for folder in os.listdir(folders):#遍历所有类别的文件夹
for file in os.listdir(folders+folder):
file_list.append(file)
corpora_documents=[]
for folder in os.listdir(folders):#遍历所有类别的文件夹
for file in os.listdir(folders+folder):#遍历每一类文件夹中的每个文件
f=open(folders+folder+'/'+file)
strs=f.read().replace('\n', '')#去掉回车键
item_seg=strs.split()#根据空格保存分词后的结果
corpora_documents.append(item_seg)
#下面部分代码来自[2]
# 生成字典和向量语料
dictionary = corpora.Dictionary(corpora_documents)
# 通过下面一句得到语料中每一篇文档对应的稀疏向量(这里是bow向量)
corpus = [dictionary.doc2bow(text) for text in corpora_documents]
# 向量的每一个元素代表了一个word在这篇文档中出现的次数
# print(corpus)
# corpora.MmCorpus.serialize('corpuse.mm',corpus)#保存生成的语料
# corpus=corpora.MmCorpus('corpuse.mm')#加载
# corpus是一个返回bow向量的迭代器。下面代码将完成对corpus中出现的每一个特征的IDF值的统计工作
tfidf_model = models.TfidfModel(corpus)
corpus_tfidf = tfidf_model[corpus]
#根据关键词返回最相关的一篇文章(模仿搜索引擎)
def get_article(index):
best_matchfile=file_list[index]
for folder in os.listdir(folders):#遍历所有类别的文件夹
for file in os.listdir(folders+folder):#遍历每一类文件夹中的每个文件
if file==best_matchfile:
f=open(folders+folder+'/'+file)
strs=f.read().replace('\n', '')#去掉回车键
return strs#返回最匹配的文章内容
question='邹家华 矿产'
print("-------------------下面是tfidf模型(第1个提问)----------------------------------------------------")
similarity = similarities.Similarity('Similarity-tfidf-index', corpus_tfidf,num_features=len(dictionary.dfs))
#注意这里的num_features如果随意改的话,可能会导致segmentation fault(原因不明).
test_data_1 = question
test_cut_raw_1 = list(jieba.cut(test_data_1)) # ['北京', '雾', '霾', '红色', '预警']
test_corpus_1 = dictionary.doc2bow(test_cut_raw_1) # [(51, 1), (59, 1)],即在字典的56和60的地方出现重复的字段,这个值可能会变化
similarity.num_best = 5
test_corpus_tfidf_1 = tfidf_model[test_corpus_1] # 根据之前训练生成的model,生成query的IFIDF值,然后进行相似度计算
# [(51, 0.7071067811865475), (59, 0.7071067811865475)]
print(similarity[test_corpus_tfidf_1]) # 返回最相似的样本材料,(index_of_document, similarity) tuples
best_match_article=get_article(similarity[test_corpus_tfidf_1][0][0])
print("搜索得到最匹配的文章是:",best_match_article)
print("-------------------下面是tfidf模型(第2个提问)----------------------------------------------------")
test_data_2 = question
test_cut_raw_2 = list(jieba.cut(test_data_2))
test_corpus_2 = dictionary.doc2bow(test_cut_raw_2)
test_corpus_tfidf_2 = tfidf_model[test_corpus_2]
similarity.num_best = 3
print(similarity[test_corpus_tfidf_2]) # 返回最相似的样本材料,(index_of_document, similarity) tuples
print("-------------------下面是LSI模型-----------------------------------")
# 使用LSI模型进行相似度计算
lsi = models.LsiModel(corpus_tfidf)
corpus_lsi = lsi[corpus_tfidf]
similarity_lsi = similarities.Similarity('Similarity-LSI-index', corpus_lsi, num_features=400, num_best=2)
# save
# LsiModel.load(fname, mmap='r')#加载
test_data_3 = question
test_cut_raw_3 = list(jieba.cut(test_data_3)) # 1.分词
test_corpus_3 = dictionary.doc2bow(test_cut_raw_3) # 2.转换成bow向量(bow=bag of words)
test_corpus_tfidf_3 = tfidf_model[test_corpus_3] # 3.计算tfidf值
test_corpus_lsi_3 = lsi[test_corpus_tfidf_3] # 4.计算lsi值
# lsi.add_documents(test_corpus_lsi_3) #更新LSI的值
print(similarity_lsi[test_corpus_lsi_3])