import numpy as np
from collections import Counter
import jieba
from gensim.summarization import bm25 # gensim version: 3.8.3
未分词的语料,建模前需要分词。
同时,也需要去停用词,当前未去停用词,后面可以看下对搜索的影响。
document_list = ["行政机关强行解除行政协议造成损失,如何索取赔偿?",
"借钱给朋友到期不还得什么时候可以起诉?怎么起诉?",
"我在微信上被骗了,请问被骗多少钱才可以立案?",
"公民对于选举委员会对选民的资格申诉的处理决定不服,能不能去法院起诉吗?",
"有人走私两万元,怎么处置他?",
"法律上餐具、饮具集中消毒服务单位的责任是不是对消毒餐具、饮具进行检验?"]
document_list_cut = [list(jieba.cut(doc)) for doc in document_list]
print(document_list_cut)
Building prefix dict from the default dictionary ... Loading model from cache C:\Users\aidway\AppData\Local\Temp\jieba.cache Loading model cost 0.614 seconds. Prefix dict has been built successfully.
[['行政', '机关', '强行', '解除', '行政', '协议', '造成', '损失', ',', '如何', '索取', '赔偿', '?'], ['借钱', '给', '朋友', '到期', '不', '还', '得', '什么', '时候', '可以', '起诉', '?', '怎么', '起诉', '?'], ['我', '在', '微信', '上', '被', '骗', '了', ',', '请问', '被', '骗', '多少', '钱', '才', '可以', '立案', '?'], ['公民', '对于', '选举', '委员会', '对', '选民', '的', '资格', '申诉', '的', '处理', '决定', '不服', ',', '能', '不能', '去', '法院', '起诉', '吗', '?'], ['有人', '走私', '两万元', ',', '怎么', '处置', '他', '?'], ['法律', '上', '餐具', '、', '饮具', '集中', '消毒', '服务', '单位', '的', '责任', '是不是', '对', '消毒', '餐具', '、', '饮具', '进行', '检验', '?']]
class BM25_Model(object):
def __init__(self, documents_list, k1=2, k2=1, b=0.75):
# 文本列表,其各个文档已分词
self.documents_list = documents_list
# 文本总个数
self.documents_number = len(documents_list)
# 文本库中文本的平均长度
self.avg_documents_len = sum([len(document) for document in documents_list]) / self.documents_number
# 存储documents_list的每个文本中每个词的词频
self.f = []
# 存储每个词汇的逆文档频率
self.W = {}
self.k1 = k1
self.k2 = k2
self.b = b
# 类初始化
self.init()
def init(self):
df = {}
for document in self.documents_list:
temp = {}
for word in document:
# 存储每个文档中每个词的词频
temp[word] = temp.get(word, 0) + 1
self.f.append(temp)
for key in temp.keys():
df[key] = df.get(key, 0) + 1
for key, value in df.items():
# 公式中的W,相当于IDF
self.W[key] = np.log((self.documents_number - value + 0.5) / (value + 0.5))
def get_score(self, index, query):
score = 0.0
document_len = len(self.f[index])
qf = Counter(query)
for q in query:
if q not in self.f[index]:
continue
K = self.k1 * (1 - self.b + self.b * document_len / self.avg_documents_len)
score += self.W[q] * (self.f[index][q] * (self.k1 + 1) / (self.f[index][q] + K)) * (qf[q] * (self.k2 + 1) / (qf[q] + self.k2))
return score
def get_documents_score(self, query):
score_list = []
for i in range(self.documents_number):
score_list.append(self.get_score(i, query))
return score_list
bm25_model = BM25_Model(document_list_cut)
print(bm25_model.documents_list)
[['行政', '机关', '强行', '解除', '行政', '协议', '造成', '损失', ',', '如何', '索取', '赔偿', '?'], ['借钱', '给', '朋友', '到期', '不', '还', '得', '什么', '时候', '可以', '起诉', '?', '怎么', '起诉', '?'], ['我', '在', '微信', '上', '被', '骗', '了', ',', '请问', '被', '骗', '多少', '钱', '才', '可以', '立案', '?'], ['公民', '对于', '选举', '委员会', '对', '选民', '的', '资格', '申诉', '的', '处理', '决定', '不服', ',', '能', '不能', '去', '法院', '起诉', '吗', '?'], ['有人', '走私', '两万元', ',', '怎么', '处置', '他', '?'], ['法律', '上', '餐具', '、', '饮具', '集中', '消毒', '服务', '单位', '的', '责任', '是不是', '对', '消毒', '餐具', '、', '饮具', '进行', '检验', '?']]
print(bm25_model.documents_number)
6
print(bm25_model.avg_documents_len)
15.666666666666666
print(bm25_model.f)
[{'行政': 2, '机关': 1, '强行': 1, '解除': 1, '协议': 1, '造成': 1, '损失': 1, ',': 1, '如何': 1, '索取': 1, '赔偿': 1, '?': 1}, {'借钱': 1, '给': 1, '朋友': 1, '到期': 1, '不': 1, '还': 1, '得': 1, '什么': 1, '时候': 1, '可以': 1, '起诉': 2, '?': 2, '怎么': 1}, {'我': 1, '在': 1, '微信': 1, '上': 1, '被': 2, '骗': 2, '了': 1, ',': 1, '请问': 1, '多少': 1, '钱': 1, '才': 1, '可以': 1, '立案': 1, '?': 1}, {'公民': 1, '对于': 1, '选举': 1, '委员会': 1, '对': 1, '选民': 1, '的': 2, '资格': 1, '申诉': 1, '处理': 1, '决定': 1, '不服': 1, ',': 1, '能': 1, '不能': 1, '去': 1, '法院': 1, '起诉': 1, '吗': 1, '?': 1}, {'有人': 1, '走私': 1, '两万元': 1, ',': 1, '怎么': 1, '处置': 1, '他': 1, '?': 1}, {'法律': 1, '上': 1, '餐具': 2, '、': 2, '饮具': 2, '集中': 1, '消毒': 2, '服务': 1, '单位': 1, '的': 1, '责任': 1, '是不是': 1, '对': 1, '进行': 1, '检验': 1, '?': 1}]
print(bm25_model.W)
{'行政': 1.2992829841302609, '机关': 1.2992829841302609, '强行': 1.2992829841302609, '解除': 1.2992829841302609, '协议': 1.2992829841302609, '造成': 1.2992829841302609, '损失': 1.2992829841302609, ',': -0.587786664902119, '如何': 1.2992829841302609, '索取': 1.2992829841302609, '赔偿': 1.2992829841302609, '?': -2.5649493574615367, '借钱': 1.2992829841302609, '给': 1.2992829841302609, '朋友': 1.2992829841302609, '到期': 1.2992829841302609, '不': 1.2992829841302609, '还': 1.2992829841302609, '得': 1.2992829841302609, '什么': 1.2992829841302609, '时候': 1.2992829841302609, '可以': 0.5877866649021191, '起诉': 0.5877866649021191, '怎么': 0.5877866649021191, '我': 1.2992829841302609, '在': 1.2992829841302609, '微信': 1.2992829841302609, '上': 0.5877866649021191, '被': 1.2992829841302609, '骗': 1.2992829841302609, '了': 1.2992829841302609, '请问': 1.2992829841302609, '多少': 1.2992829841302609, '钱': 1.2992829841302609, '才': 1.2992829841302609, '立案': 1.2992829841302609, '公民': 1.2992829841302609, '对于': 1.2992829841302609, '选举': 1.2992829841302609, '委员会': 1.2992829841302609, '对': 0.5877866649021191, '选民': 1.2992829841302609, '的': 0.5877866649021191, '资格': 1.2992829841302609, '申诉': 1.2992829841302609, '处理': 1.2992829841302609, '决定': 1.2992829841302609, '不服': 1.2992829841302609, '能': 1.2992829841302609, '不能': 1.2992829841302609, '去': 1.2992829841302609, '法院': 1.2992829841302609, '吗': 1.2992829841302609, '有人': 1.2992829841302609, '走私': 1.2992829841302609, '两万元': 1.2992829841302609, '处置': 1.2992829841302609, '他': 1.2992829841302609, '法律': 1.2992829841302609, '餐具': 1.2992829841302609, '、': 1.2992829841302609, '饮具': 1.2992829841302609, '集中': 1.2992829841302609, '消毒': 1.2992829841302609, '服务': 1.2992829841302609, '单位': 1.2992829841302609, '责任': 1.2992829841302609, '是不是': 1.2992829841302609, '进行': 1.2992829841302609, '检验': 1.2992829841302609}
query = "走私了两万元,在法律上应该怎么量刑?"
query_cut = list(jieba.cut(query))
scores = bm25_model.get_documents_score(query_cut)
print(scores)
[-3.5705685072552242, -3.4672839081009865, 0.03434740668591951, -2.769693328057791, 0.04450649880429003, -0.6707441325509551]
为何相似度出现负数?
因为某些单词,如?,在语料库出现的比较频繁,导致IDF小于0。
如何进行优化:
分词后去停用词。
print('查询内容:', query)
print('搜索结果:', document_list[np.argmax(scores)])
查询内容: 走私了两万元,在法律上应该怎么量刑? 搜索结果: 有人走私两万元,怎么处置他?
qsSim = bm25.BM25(document_list_cut)
scores_gensim = qsSim.get_scores(query_cut)
scores_gensim
[0.6260184105014617, 1.0178936186081802, 3.6255691142296627, 0.5012767346081815, 4.827497210761461, 1.935229385286728]
print('查询内容:', query)
print('搜索结果:', document_list[np.argmax(scores_gensim)])
查询内容: 走私了两万元,在法律上应该怎么量刑? 搜索结果: 有人走私两万元,怎么处置他?