1. 程式人生 > 其它 >基於發電廠知識問答庫的檢索式問答系統(python有程式碼)

基於發電廠知識問答庫的檢索式問答系統(python有程式碼)

技術標籤:電氣 和電力人工智慧nlp演算法python

之前寫過基於倒排表的問答系統。
基於倒排表的電力排程知識問答系統構建
問答系統所需要的資料已經提供,對於每一個問題都可以找得到相應的答案,所以可以理解為每一個樣本資料是 <問題、答案>。 那系統的核心是當用戶輸入一個問題的時候,首先要找到跟這個問題最相近的已經儲存在庫裡的問題,然後直接返回相應的答案即可。
由於作者是學電氣的,這裡以發電廠知識文字來構建問答系統

該篇是低配版的問答系統,思路不如倒排表。

思路
1,將發電廠知識問答資料集(問題.txt & 答案.txt)通過預處理,整合為格式規範的資料。
2,基於詞袋模型和TFIDF模型,採用餘弦相似度作為度量標準,對測試問題語料庫中的問題進行文字相似度計算,找出相似度較高的問題作為相似問題集合。

3,將相似問題集合中的問題進行排序,同時返回其對應的答案給使用者。

文字資料集準備
答案.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("火電廠"))

總結
該思路不如倒排表。有空參照下另一篇吧
倒排表速度快。
連結如下:

基於倒排表的電力排程知識問答系統構建

在這裡插入圖片描述
作者:電力-餘登武
在這裡插入圖片描述