目的
给定一个或多个搜索词,如“高血压 患者”,从已有的若干篇文本中找出最相关的(n篇)文本。
文本检索(text retrieve)的常用策略是:用一个ranking function根据搜索词对所有文本进行排序,选取前n个,就像百度搜索一样。
显然,ranking function是决定检索效果最重要的因素,本文选用了在实际应用中效果很好的BM25。BM25其实只用到了一些基础的统计和文本处理的方法,没有很高深的算法。
gensim中代码写得很清楚,我们可以直接利用。
import jieba.posseg as pseg
import codecs
from gensim import corpora
from gensim.summarization import bm25
import os
import re
构建停用词表
stop_words = '/Users/yiiyuanliu/Desktop/nlp/demo/stop_words.txt'
stopwords = codecs.open(stop_words,'r',encoding='utf8').readlines()
stopwords = [ w.strip() for w in stopwords ]
结巴分词后的停用词性 [标点符号、连词、助词、副词、介词、时语素、‘的’、数词、方位词、代词]
stop_flag = ['x', 'c', 'u','d', 'p', 't', 'uj', 'm', 'f', 'r']
对一篇文章分词、去停用词
def tokenization(filename):
result = []
with open(filename, 'r') as f:
text = f.read()
words = pseg.cut(text)
for word, flag in words:
if flag not in stop_flag and word not in stopwords:
result.append(word)
return result
对目录下的所有文本进行预处理,构建字典
corpus = [];
dirname = '/Users/yiiyuanliu/Desktop/nlp/demo/articles'
filenames = []
for root,dirs,files in os.walk(dirname):
for f in files:
if re.match(ur'[\u4e00-\u9fa5]*.txt', f.decode('utf-8')):
corpus.append(tokenization(f))
filenames.append(f)
dictionary = corpora.Dictionary(corpus)
print len(dictionary)
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/1q/5404x10d3k76q2wqys68pzkh0000gn/T/jieba.cache
Loading model cost 0.328 seconds.
Prefix dict has been built succesfully.
建立词袋模型
打印了第一篇文本按词频排序的前5个词
doc_vectors = [dictionary.doc2bow(text) for text in corpus]
vec1 = doc_vectors[0]
vec1_sorted = sorted(vec1, key=lambda (x,y) : y, reverse=True)
print len(vec1_sorted)
for term, freq in vec1_sorted[:5]:
print dictionary[term]
用gensim建立BM25模型
bm25Model = bm25.BM25(corpus)
根据gensim源码,计算平均逆文档频率
average_idf = sum(map(lambda k: float(bm25Model.idf[k]), bm25Model.idf.keys())) / len(bm25Model.idf.keys())
假设用户输入了搜索词“高血压 患者 药物”,利用BM25模型计算所有文本与搜索词的相关性
query_str = '高血压 患者 药物'
query = []
for word in query_str.strip().split():
query.append(word.decode('utf-8'))
scores = bm25Model.get_scores(query,average_idf)
# scores.sort(reverse=True)
print scores
[4.722034069722618, 4.5579610648148625, 2.859958016641194, 3.388613898734133, 4.6281563584251995, 4.730042214103296, 1.447106736835707, 2.595169814422283, 2.894213473671414, 2.952010252059601, 3.987044912721877, 2.426869660460219, 1.1583806884161147, 0, 3.242214688067997, 3.6729065940310752, 3.025338037306947, 1.57823130047124, 2.6054874252518214, 3.4606547596124635, 1.1583806884161147, 2.412854586446401, 1.7354863870557247, 1.447106736835707, 3.571235274862516, 2.6054874252518214, 2.695780408029825, 2.3167613768322295, 4.0309963518837595, 0, 2.894213473671414, 3.306255023356817, 3.587349029341776, 3.4401107112269824, 3.983307351035947, 0, 4.508767501123564, 3.6289862140766926, 3.6253442838304633, 4.248297326100691, 3.025338037306947, 3.602635199166345, 3.4960329155028464, 3.3547048399034876, 1.57823130047124, 4.148340973502125, 1.1583806884161147]
idx = scores.index(max(scores))
print idx
找到最相关的文本
fname = filenames[idx]
print fname
关于降压药的五个问题.txt
with open(fname,'r') as f:
print f.read()
高血压的重要治疗方式之一,就是口服降压药。对于不少刚刚被确诊的“高血压新手”来说,下面这些关于用药的事情,是必须知道的。
1. 贵的药,真的比便宜的药好用吗?
事实上,降压药物的化学机构和作用机制不一样。每一种降压药,其降压机理和适应人群都不一样。只要适合自己的病情和身体状况,就是好药。因此,不存在“贵重降压药一定比便宜的降压药好使”这一说法。
2. 能不吃药就不吃药,靠身体调节血压,这种想法对吗?
这种想法很幼稚。其实,高血压是典型的,应该尽早服药的疾病。如果服药太迟,高血压对重要脏器持续形成伤害,会让我们的身体受很大打击。所以,高血压患者尽早服药,是对身体的最好的保护。
3. 降压药是不是得吃一辈子?
对于这个问题,中医和西医有着不同的认识。西医认为,降压药服用之后不应该停用,以免血压形成波动,造成对身体的进一步伤害。中医则认为,通过适当的运动和饮食调节,早期的部分高血压患者,可以在服药之后的某段时间里停药。总之,处理这一问题的时候,我们还是要根据自己的情况而定。对于高血压前期,或者轻度高血压的人来说,在生活方式调节能够让血压稳定的情况下,可以考虑停药,采取非药物疗法。对于中度或者重度的高血压患者来说,就不能这么做了。
4. 降压药是不是要早晨服用?
一般来说,长效的降压药物,都是在早晨服用的。但是,我们也可以根据高血压患者的波动情况,适当改变服药时间。
5. 降压药是不是一旦服用就不能轻易更换?