一、bm25的应用和基础


医学领域,BM25算法的应用,文档分类相似度识别以及疾病、手术等实体的相似度匹配。文档的处理相对简单,可以直接调用相关算法包,实体单词的相似度匹配需要对文本做相关的处理。对比研究,在文档中,表示特征的主要是单词,而在实体名词(疾病、手术、药品名称)中,表示特征的是字或者由n-gram切分的元素,当用字表示特征时,文本的语义会丢失,所以我建议用字和n-gram(n>=2)分词元素作为特征。

BM25算法相关性分数的构成:

分为两个类别,一个是计算文档与文档的相似度,另一个是计算词与词的相似度,如果计算的是词(或称为短文本)与词之间的相似度,那么就要用n-gram切词,进而以每个元素为单位进行计算。

以文档相似度为例:

相关性分数公式如下:

相似度匹配 python 相似度匹配算法me_python

里面包含三部分计算:

(1)元素的权重,计算tf-idf,文档的元素就是词,短文本的元素为字或n-gram元素:

相似度匹配 python 相似度匹配算法me_词频_02

其中N表示索引中全部文档数,

相似度匹配 python 相似度匹配算法me_相似度_03

为包含了

相似度匹配 python 相似度匹配算法me_python_04

的文档的个数。依据IDF的作用,对于某个

相似度匹配 python 相似度匹配算法me_python_04

,包含

相似度匹配 python 相似度匹配算法me_python_04

的文档数越多,说明

相似度匹配 python 相似度匹配算法me_python_04

重要性越小,或者区分度越低,IDF越小,因此IDF可以用来刻画

相似度匹配 python 相似度匹配算法me_python_04

与文档的相似性。

 (2)单词和文档的相关性

相似度匹配 python 相似度匹配算法me_数据挖掘_09

 其中,是单词t在文档d中的词频,是文档d的长度,是所有文档的平均长度,变量是一个正的参数,用来标准化文章词频的范围,当=0,就是一个二元模型(binary model)(没有词频),一个更大的值对应使用更原始的词频信息。b是另一个可调参数(0<b<1),他是用决定使用文档长度来表示信息量的范围:当b为1,是完全使用文档长度来权衡词的权重,当b为0表示不使用文档长度。

(3)单词和查询的相关性: 

 

相似度匹配 python 相似度匹配算法me_相似度_10

 这里

相似度匹配 python 相似度匹配算法me_相似度_11

表示单词t在query中的词频,

相似度匹配 python 相似度匹配算法me_数据挖掘_12

是一个可调正参数,来矫正query中的词频范围。

最终相似度公式

相似度匹配 python 相似度匹配算法me_相似度匹配 python_13

二、相似度分类实例(疾病相似度分类)

现在bm25实现的开源包有很多,在这里我是用gensim实现。

gensim包的下载配置:清华镜像源

pip install --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple gensim

基本使用方法,以短文本分类为实例

corpus为标准的单词分类集合,主要包含了每类疾病的标准分类特征,corpus_dic为每个特征集合对应的分类标签,key为分类标签,value为特征。test_word为测试文本

处理过程:用测试集的特征和标准特征计算相关性,对测试样本的每个元素的相关性分数求和,即为总的相关性分数:

from gensim.summarization import bm25
import jieba

def gensim_bm25_word_classification(test_word):
    corpus = [
        ['高','血','压','高血','血压'],
        ['糖','尿','病'],
        ['精','神','病']
        ]
    corpus_dic = {
        '高血压':['高','血','压','高血','血压'],
        '糖尿病':['糖','尿','病'],
        '精神病':['精','神','病']
    }
    bm25Model = bm25.BM25(corpus)
    #将str转为list
    test_word = list(test_word)

    scores = bm25Model.get_scores(test_word)
    print('测试短文本:', test_word)
    for i, j in zip(scores, corpus):
        for m in corpus_dic.keys():
            if j == corpus_dic[m]:
                word_name = m
        print('分值:{},原词:{}'.format(i, word_name))

 测试:高血压1级

if __name__ == '__main__':
    test_word = '高血压1级'
    gensim_bm25_word_classification(test_word)

分类结果打印:

相似度匹配 python 相似度匹配算法me_相似度匹配 python_14

 高血压类的相关性分数为1.31,远高于其他分类,故分类结果为:高血压。

二、文本分类

需要jieba分词和stopword停用词设置,非常简单。