北京 上海巡回站 | NVIDIA DLI深度学习培训
2018年1月26/1月12日

NVIDIA 深度学习学院 带你快速进入火热的DL领域
阅读全文                                                
>

作者:刘艺原,现浙江大学 生物医学工程研究生。

正文共5788个字,5张图,预计阅读时间:15分钟。

目的

给定一个或多个搜索词,如“高血压 患者”,从已有的若干篇文本中找出最相关的(n篇)文本。

理论知识

文本检索(text retrieve)的常用策略是:用一个ranking function根据搜索词对所有文本进行排序,选取前n个,就像百度搜索一样。

显然,ranking function是决定检索效果最重要的因素,本文选用了在实际应用中效果很好的BM25。BM25其实只用到了一些基础的统计和文本处理的方法,没有很高深的算法。

BM25

上图是BM25的公式,对于一个搜索q和所有文本,计算每一篇文本d的权重。整个公式其实是TF-IDF的改进:

  • 第一项c(w,q)就是搜索q中词w的词频

  • 第三项是词w的逆文档频率,M是所有文本的个数,df(w)是出现词w的文本个数

  • 中间的第二项是关键,实质是词w的TF值的变换,c(w,d)是词w在文本d中的词频。首先是一个TF Transformation,目的是防止某个词的词频过大,经过下图中公式的约束,词频的上限为k+1,不会无限制的增长。例如,一个词在文本中的词频无论是50还是100,都说明文本与这个词有关,但相关度不可能是两倍关系。

    TF Transformation

  • 上图的公式分母中的k还乘了一个系数,目的是归一化文本长度。归一化公式中,b是[0,1]之间的常数,avdl是平均文本长度,d是文本d的长度。显然,d比平均值大,则normalizer大于1,代入BM25最终的权重变小,反之亦然。

length normalization

Python实现

下面通过一个例子来实现根据BM25来进行文本检索。现在从网上爬下来了几十篇健康相关的文章,部分如下图所示。模拟输入搜索词,如“高血压 患者 药物”,搜素最相关的文章。

文本列表

python的实现用到了gensim库,其中的BM25实现的源码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Licensed under the GNU LGPL v2.1 - http://www.gnu.org/licenses/lgpl.html
 import math
from six import iteritems
from six.moves import xrange
 # BM25 parameters.

PARAM_K1 = 1.5
PARAM_B = 0.75
EPSILON = 0.25
 class BM25(object):    
def __init__(self, corpus):        
self.corpus_size = len(corpus)        
self.avgdl = sum(map(lambda x: float(len(x)), corpus)) / self.corpus_size        self.corpus = corpus        
self.f = []        
self.df = {}        
self.idf = {}        
self.initialize()    
def initialize(self):      
 for document in self.corpus:            
frequencies = {}            
for word in document:

if word not in frequencies:                    
frequencies[word] = 0                
frequencies[word] += 1            
self.f.append(frequencies)          
 for word, freq in iteritems(frequencies):                
if word not in self.df:                    
self.df[word] = 0                
self.df[word] += 1        
for word, freq in iteritems(self.df):            
self.idf[word] = math.log(self.corpus_size - freq + 0.5) - math.log(freq + 0.5)    
def get_score(self, document, index, average_idf):        
score = 0        
for word in document:

if word not in self.f[index]:                
continue            
idf = self.idf[word] if self.idf[word] >= 0 else EPSILON * average_idf            
score += (idf * self.f[index][word] * (PARAM_K1 + 1)                      
/ (self.f[index][word] + PARAM_K1 * (1 - PARAM_B + PARAM_B * self.corpus_size / self.avgdl)))

return score    
def get_scores(self, document, average_idf):        
scores = []        
for index in xrange(self.corpus_size):            
score = self.get_score(document, index, average_idf)            
scores.append(score)      
 return scores
 def get_bm25_weights(corpus):    
bm25 = BM25(corpus)    
average_idf = sum(map(lambda k: float(bm25.idf[k]), bm25.idf.keys())) / len(bm25.idf.keys())    
weights = []    
for doc in corpus:        
scores = bm25.get_scores(doc, average_idf)

weights.append(scores)    
return weights

gensim中代码写得很清楚,我们可以直接利用。

import jieba.posseg as psegimport codecsfrom gensim import corporafrom gensim.summarization import bm25import osimport 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.

2552

建立词袋模型

打印了第一篇文本按词频排序的前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]

76 高血压 患者 药物 血压 治疗

用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

5

找到最相关的文本

fname = filenames[idx]

print fname

关于降压药的五个问题.txt

with open(fname,'r') as f:

print f.read()

高血压的重要治疗方式之一,就是口服降压药。对于不少刚刚被确诊的“高血压新手”来说,下面这些关于用药的事情,是必须知道的。 1. 贵的药,真的比便宜的药好用吗?      事实上,降压药物的化学机构和作用机制不一样。每一种降压药,其降压机理和适应人群都不一样。只要适合自己的病情和身体状况,就是好药。因此,不存在“贵重降压药一定比便宜的降压药好使”这一说法。 2. 能不吃药就不吃药,靠身体调节血压,这种想法对吗?     这种想法很幼稚。其实,高血压是典型的,应该尽早服药的疾病。如果服药太迟,高血压对重要脏器持续形成伤害,会让我们的身体受很大打击。所以,高血压患者尽早服药,是对身体的最好的保护。 3. 降压药是不是得吃一辈子?      对于这个问题,中医和西医有着不同的认识。西医认为,降压药服用之后不应该停用,以免血压形成波动,造成对身体的进一步伤害。中医则认为,通过适当的运动和饮食调节,早期的部分高血压患者,可以在服药之后的某段时间里停药。总之,处理这一问题的时候,我们还是要根据自己的情况而定。对于高血压前期,或者轻度高血压的人来说,在生活方式调节能够让血压稳定的情况下,可以考虑停药,采取非药物疗法。对于中度或者重度的高血压患者来说,就不能这么做了。 4. 降压药是不是要早晨服用?      一般来说,长效的降压药物,都是在早晨服用的。但是,我们也可以根据高血压患者的波动情况,适当改变服药时间。 5. 降压药是不是一旦服用就不能轻易更换?      高血压病人一旦服用了某种降压药物,就不要轻易更换。只要能维持血压在正常范围而且稳定,就不用换药。只有在原有药物不能起到控制作用的时候,再考虑更换服药方案。对于新发高血压病人来说,长效降压药若要达到稳定的降压效果,往往需要4到6周或者更长时间。如果经过4到6周也实现不了好的控制效果,可以考虑加第二种药物来联合降压,不必盲目换药。

参考资料

Coursera: Text Mining and Analytics(https://www.coursera.org/learn/text-mining)

原文链接:http://www.jianshu.com/p/ff28004efb8a

查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:

www.leadai.org

请关注人工智能LeadAI公众号,查看更多专业文章

大家都在看


LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理(一)

最全常见算法工程师面试题目整理(二)

TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础

python根据BM25实现文本检索相关推荐

  1. python 实现文本搜索_python根据BM25实现文本检索

    作者:刘艺原,现浙江大学 生物医学工程研究生. 正文共5788个字,5张图,预计阅读时间:15分钟. 目的 给定一个或多个搜索词,如"高血压 患者",从已有的若干篇文本中找出最相关 ...

  2. 相关性算法BM25的python实现

    计算原理 第一项c(w,q)就是搜索q中词w的词频 第三项是词w的逆文档频率,M是所有文本的个数,df(w)是出现词w的文本个数 中间的第二项是关键,实质是词w的TF值的变换,c(w,d)是词w在文本 ...

  3. 利用python进行tf-idf算法绘制词云图_利用python实现通过TF-IDF和BM25提取文章关键词...

    使用TF-IDF和BM25提取文章关键词 评估方法: 人工从文章中提取1-5个关键词,和机器提取的关键词做比较 召回 = 机器提词∩人工提词 / 人工提词 准确 = 机器提词∩人工提词 / 机器提词 ...

  4. 文本相似度bm25算法的原理以及Python实现(jupyter notebook)

    今天我们一起来学习一下自然语言处理中的bm25算法,bm25算法是常见的用来计算query和文章相关度的相似度的.其实这个算法的原理很简单,就是将需要计算的query分词成w1,w2,-,wn,然后求 ...

  5. TF-IDF和BM25算法原理及python实现

    目录 前言 一.TF-IDF TF定义: 逆文本频率指数(Inverse Document Frequency,IDF) TF-IDF(Term Frequency-inverse Document ...

  6. BM25算法,python实现(源代码)

    BM25算法,python实现 直接上代码吧,公式在维基百科上搜一下.有帮助的话就点赞收藏一下吧,有问题直接评论,会进行答复. import json import math import os im ...

  7. python实现文本检索-文本相似度算法

    目的 给定一个或多个搜索词,如"高血压 患者",从已有的若干篇文本中找出最相关的(n篇)文本. 理论知识 文本检索(text retrieve)的常用策略是:用一个ranking ...

  8. Python自用工具包PyTls

    我们搞了个python的工具包PyTls. 做这件事的初衷是发生了一个星期要用python同时开发3个项目的情况,我发现了两个现象:1.有很多定制化的需求是极度高频反复重写的:2.有很多功能之前写过, ...

  9. python 利用 whoosh 搭建轻量级搜索

      本文将简单介绍Python中的一个轻量级搜索工具Whoosh,并给出相应的使用示例代码. Whoosh简介   Whoosh由Matt Chaput创建,它一开始是一个为Houdini 3D动画软 ...

最新文章

  1. 我们不雇佣数理逻辑不好的学生
  2. linux命令lsof
  3. 进程通信QSharedMemory
  4. 四种方法取表里n到m条纪录:[转]
  5. iptables中关于limit和limit-burst的解释
  6. 习题7-2 求一批整数中出现最多的个位数字 (20分)
  7. 【UVA - 10037】Bridge(过河问题,经典贪心)
  8. CentOS7 防火墙关闭
  9. 20道必须掌握的C++面试题
  10. Application.messagebox对话框样式
  11. 数据库配置文件,db.properties、jdbc.properties
  12. [转]ASP.NET在线用户列表精确版—解决用户意外退出在线列表无法及时更新问
  13. Intellij IDEA中程序播放音乐 没声音
  14. Multisim14仿真基本模拟电路之 10.2单管共射放大电路的仿真实验与分析
  15. AXI总线学习-------从零开始详细学-------------连载(7)读写处理架构,burst介绍,burst细节定义(burst type burst address)
  16. PCIe Expansion Roms
  17. “M1芯片”电脑杀手:Windows笔记本电脑目前岌岌可危
  18. GO语言实战之类型的本质
  19. 认识计算机微课导学单,微课“任务单”与“导学案”之比较
  20. 自定义创建rabbitMQ的channel连接池

热门文章

  1. 关闭mysql方法_启动和关闭MySQL的方法
  2. pb90代码如何连接sql2008r2_RabbitMQ各种交换机机制,代码实践篇
  3. 如何设置工作流到了某一节点自动执行java方法_2019年JAVA最常见面试题汇总(收藏)...
  4. Android application project 各个文件夹作用
  5. Dais-CMX系列现代计算机组成原理,01 十六位机运算器实验
  6. 西交大计算机考博学术英语,2018年西安交通大学考博英语真题
  7. it有啥好咨询的_小经验 | 埃森哲Accenture管理咨询+IT咨询实习
  8. ASP.net Web API综合示例
  9. 二、MyBatis系列:全局配置文件
  10. eclipse3.1.1汉化版安装