基於發電廠知識問答庫的檢索式問答系統(python有程式碼)
阿新 • • 發佈:2020-12-27
之前寫過基於倒排表的問答系統。
基於倒排表的電力排程知識問答系統構建
問答系統所需要的資料已經提供,對於每一個問題都可以找得到相應的答案,所以可以理解為每一個樣本資料是 <問題、答案>。 那系統的核心是當用戶輸入一個問題的時候,首先要找到跟這個問題最相近的已經儲存在庫裡的問題,然後直接返回相應的答案即可。
由於作者是學電氣的,這裡以發電廠知識文字來構建問答系統
該篇是低配版的問答系統,思路不如倒排表。
思路
1,將發電廠知識問答資料集(問題.txt & 答案.txt)通過預處理,整合為格式規範的資料。
2,基於詞袋模型和TFIDF模型,採用餘弦相似度作為度量標準,對測試問題語料庫中的問題進行文字相似度計算,找出相似度較高的問題作為相似問題集合。
文字資料集準備
答案.txt
問題.txt
第一步:讀取資料
#第一步:讀取資料
def read_corpus(file):
with open(file,'r',encoding='utf8',errors='ignore') as f:
list = []
lines = f.readlines()
for i in lines:
list.append(i)
return list
questions = read_corpus( './問題.txt')
answers = read_corpus('./答案.txt')
print('Example:')
print('Question',questions[0])
print('Answer',answers[0])
第二步:預處理
#第二步:預處理
import re
import jieba
def filter_out_category(input):
new_input = re.sub('[\u4e00-\u9fa5]{2,5}\\/','',input) #過濾掉非漢字,即標點符號
return new_input
def filter_out_punctuation (input):
new_input = re.sub('([a-zA-Z0-9])','',input)#過濾掉字母和數字
new_input = ''.join(e for e in new_input if e.isalnum())
return new_input
def word_segmentation(input):
new_input = ','.join(jieba.cut(input))#分詞
return new_input
def preprocess_text(data):
new_data = []
for q in data:
q = filter_out_category(q)#過濾掉符號
q = filter_out_punctuation(q)#過濾掉字母和數字
q = word_segmentation(q)#分詞
new_data.append(q)
return new_data
qlist = preprocess_text(questions) # 更新後的
print('questions after preprocess',qlist[0:3])
第三步:詞袋模型和TFIDF模型
#第三步:詞袋模型和tf_idf模型
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
#詞袋模型
def bow_extractor(corpus, ngram_range=(1, 1)):
vectorizer = CountVectorizer(min_df=1, ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
# # 詞袋模型特徵
def conver2BOW(data):
new_data = []
for q in data:
new_data.append(q)
bow_vectorizer, bow_X = bow_extractor(new_data)
return bow_vectorizer, bow_X
bow_vectorizer, bow_X = conver2BOW(qlist)
# print('BOW model')
print('vectorizer',bow_vectorizer.get_feature_names())
print('vector of text',bow_X[0:3].toarray())
#tf_idf
def tfidf_extractor(corpus, ngram_range=(1, 1)):
vectorizer = TfidfVectorizer(min_df=1, norm='l2', smooth_idf=True, use_idf=True, ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
# # tfidf 特徵
def conver2tfidf(data):
new_data = []
for q in data:
new_data.append(q)
tfidf_vectorizer, tfidf_X = tfidf_extractor(new_data)
return tfidf_vectorizer, tfidf_X
tfidf_vectorizer, tfidf_X = conver2tfidf(qlist)
print('TFIDF model')
print('vectorizer',tfidf_vectorizer.get_feature_names())
print('vector of text',tfidf_X[0:3].toarray())
第四步:餘弦相似度。
#第四步:餘弦相似度
import numpy as np
def idx_for_largest_cosine_sim(input, questions):
list = []
input = (input.toarray())[0]
for question in questions:
question = question.toarray()
num = float(np.matmul(question, input))
denom = np.linalg.norm(question) * np.linalg.norm(input)
if denom ==0:
cos = 0.0
else:
cos = num / denom
list.append(cos)
best_idx = list.index(max(list))
return best_idx
第五步:對測試問題語料庫中的問題進行文字相似度計算,找出相似度較高的問題作為相似問題集合
#第五步:問題求解
#詞袋模型求解
def answer_bow(input):
input = filter_out_punctuation(input)#對輸入進行過濾字母和數字
input = word_segmentation(input)#對輸入進行分詞
bow = bow_vectorizer.transform([input])#對輸入進行詞袋模型
best_idx = idx_for_largest_cosine_sim(bow, bow_X)#將輸入和問答庫的問題進行相似度計算,取出最好的哪一個
return answers[best_idx]
#tf-idf求解
def answer_tfidf(input):
input = filter_out_punctuation(input)#對輸入進行過濾字母和數字
input = word_segmentation(input)#對輸入進行分詞
bow = tfidf_vectorizer.transform([input])#對輸入進行tf-idf模型
best_idx = idx_for_largest_cosine_sim(bow, tfidf_X)#將輸入和問答庫的問題進行相似度計算,取出最好的哪一個
return answers[best_idx]
第六步:測試
#第六步:測試
print('詞袋 model',answer_bow("火電廠是什麼"))
print('tfidf model',answer_tfidf("火電廠"))
全部程式碼
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Author: yudengwu(餘登武)
# @Date : 2020/12/26
#@email:[email protected]
#第一步:讀取資料
def read_corpus(file):
with open(file,'r',encoding='utf8',errors='ignore') as f:
list = []
lines = f.readlines()
for i in lines:
list.append(i)
return list
questions = read_corpus('./問題.txt')
answers = read_corpus('./答案.txt')
#第二步:預處理
import re
import jieba
def filter_out_category(input):
new_input = re.sub('[\u4e00-\u9fa5]{2,5}\\/','',input) #過濾掉非漢字,即標點符號
return new_input
def filter_out_punctuation(input):
new_input = re.sub('([a-zA-Z0-9])','',input)#過濾掉字母和數字
new_input = ''.join(e for e in new_input if e.isalnum())
return new_input
def word_segmentation(input):
new_input = ','.join(jieba.cut(input))#分詞
return new_input
def preprocess_text(data):
new_data = []
for q in data:
q = filter_out_category(q)#過濾掉符號
q = filter_out_punctuation(q)#過濾掉字母和數字
q = word_segmentation(q)#分詞
new_data.append(q)
return new_data
qlist = preprocess_text(questions) # 更新後的問題
#第三步:詞袋模型和tf_idf模型
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
def bow_extractor(corpus, ngram_range=(1, 1)):
vectorizer = CountVectorizer(min_df=1, ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
# # 詞袋模型特徵
def conver2BOW(data):
new_data = []
for q in data:
new_data.append(q)
bow_vectorizer, bow_X = bow_extractor(new_data)
return bow_vectorizer, bow_X
bow_vectorizer, bow_X = conver2BOW(qlist)
#tf_idf
def tfidf_extractor(corpus, ngram_range=(1, 1)):
vectorizer = TfidfVectorizer(min_df=1, norm='l2', smooth_idf=True, use_idf=True, ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
# # tfidf 特徵
def conver2tfidf(data):
new_data = []
for q in data:
new_data.append(q)
tfidf_vectorizer, tfidf_X = tfidf_extractor(new_data)
return tfidf_vectorizer, tfidf_X
tfidf_vectorizer, tfidf_X = conver2tfidf(qlist)
#第四步:餘弦相似度
import numpy as np
def idx_for_largest_cosine_sim(input, questions):
list = []
input = (input.toarray())[0]
for question in questions:
question = question.toarray()
num = float(np.matmul(question, input))
denom = np.linalg.norm(question) * np.linalg.norm(input)
if denom ==0:
cos = 0.0
else:
cos = num / denom
list.append(cos)
best_idx = list.index(max(list))
return best_idx
#第五步:問題求解
#詞袋模型求解
def answer_bow(input):
input = filter_out_punctuation(input)#對輸入進行過濾字母和數字
input = word_segmentation(input)#對輸入進行分詞
bow = bow_vectorizer.transform([input])#對輸入進行詞袋模型
best_idx = idx_for_largest_cosine_sim(bow, bow_X)#將輸入和問答庫的問題進行相似度計算,取出最好的哪一個
return answers[best_idx]
#tf-idf求解
def answer_tfidf(input):
input = filter_out_punctuation(input)#對輸入進行過濾字母和數字
input = word_segmentation(input)#對輸入進行分詞
bow = tfidf_vectorizer.transform([input])#對輸入進行tf-idf模型
best_idx = idx_for_largest_cosine_sim(bow, tfidf_X)#將輸入和問答庫的問題進行相似度計算,取出最好的哪一個
return answers[best_idx]
#第六步:測試
print('詞袋 model',answer_bow("火電廠是什麼"))
print('tfidf model',answer_tfidf("火電廠"))
總結
該思路不如倒排表。有空參照下另一篇吧
倒排表速度快。
連結如下:
作者:電力-餘登武