【自然语言处理】基于python的问答系统实现

一,文件准备

该问答系统是基于已知的问题和其一一对应的答案进行实现的。首先需要准备两个文本文件,分别命名为"question.txt"和"answer.txt",分别是问题文件和答案文件,每一行是一个问题以及对应的答案。

问题文件:

中国的首都是哪个城市?

今天气温多少度?

天津距离北京有多远?

小明正在干什么?

答案文件:

北京市

26度

135公里

在上课

二,实现原理

(1)导入模块

python 复制代码
import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer

(2)读取数据集:输入为文件名,输出为列表

python 复制代码
def read_corpus(file):
    lt = []
    with open(file, 'r', encoding='utf-8') as f:
        for line in f:
            lt.append(line.strip())
return lt

执行结果:

>>> q_list = read_corpus("questions.txt")

>>> q_list

'中国的首都是哪个城市?', '今天气温多少度?', '天津距离北京有多远?', '小明正在干什么?'

>>> a_list = read_corpus("answers.txt")

>>> a_list

'北京市', '26度', '135公里', '在上课'

(3)分词

python 复制代码
def preprocess_text(q_list):
    lt = []
    for q in q_list:
        q = word_segment(q)
        lt.append(q)
return lt

preprocess_text()函数将列表q_list中的句子逐个切词,并放入lt列表中。

在preprocess_text()函数调用word_segment()函数。

python 复制代码
def word_segment(sentence):
return ",".join(jieba.cut(sentence))

>>> s = "今天气温多少度?"

>>> word_segment(s)

'今天,气温,多少度,?'

将(2)中的q_list作为参数,传递给preprocess_text(),执行结果如下:

>>> q_list = preprocess_text(q_list)

>>> q_list

'中国,的,首都,是,哪个,城市,?', '今天,气温,多少度,?', '天津,距离,北京,有多远,?', '小明,正在,干什么,?'

4 )将问题列表q_list向量化,计算每一个特征的权重

python 复制代码
def convert2tfidf(q_list):
    vectorizer, q_tfidf = calc_tfidf(q_list)
return vectorizer, q_tfidf

def calc_tfidf(q_list, ngram_range=(1, 1)):
    # 实例化一个tfidf对象
    vectorizer = TfidfVectorizer(min_df=1, norm='l2', \
                                 smooth_idf=True, \
                                 use_idf=True, \
                                 ngram_range=ngram_range)
    # 计算每个词的tfidf值
    features = vectorizer.fit_transform(q_list)
return vectorizer, features

将(3)中的问题列表q_list作为参数,传递给convert2tfidf()函数

>>> vectorizer, q_tfidf = convert2tfidf(q_list) # vectorizer是一个向量化器

>>> type(q_tfidf) # q_tfidf是一个稀疏矩阵

<class 'scipy.sparse.csr.csr_matrix'>

>>> q_tfidf.toarray().round(2) # 将稀疏矩阵转化为普通矩阵,保留两位小数

array([[0.5, 0., 0., 0.5, 0.5, 0., 0., 0., 0., 0., 0., 0., 0., 0.5],

0., 0.58, 0., 0., 0., 0.58, 0., 0., 0., 0., 0., 0.58, 0., 0.\], \[0., 0., 0.5, 0., 0., 0., 0.5, 0., 0., 0.5, 0., 0., 0.5, 0.\], \[0., 0., 0., 0., 0., 0., 0., 0.58, 0.58, 0., 0.58, 0., 0., 0.\]\]) \>\>\> q_tfidf.toarray()\[0\] # 查看q_tfidf矩阵的第一行 array(\[0.5, 0. , 0. , 0.5, 0.5, 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0.5\]) 上述矩阵就是问题"中国的首都是哪个城市?"向量化后的结果。 \>\>\> vectorizer.vocabulary_ # 向量化器vectorizer的词典 {'中国': 0, '首都': 13, '哪个': 3, '城市': 4, '今天': 1, '气温': 11, '多少度': 5, '天津': 6, '距离': 12, '北京': 2, '有多远': 9, '小明': 7, '正在': 10, '干什么': 8}

由上述可知,向量的第一个特征是"中国",第二个特征是"今天",第三个特征是"北京",依次类推其他特征。

(5)响应用户的"查询"

python 复制代码
def answer(query):
    query = word_segment(query)				# 对查询语句进行切词
    query = vectorizer.transform([query])		# 将查询语句向量化
    best_idx = idx_of_largest_sim(query, q_tfidf)	# 得到与查询语句最相似问题的下标
return a_list[best_idx]						# 返回与best_idx下标对应的答案
def idx_of_largest_sim(query, q_tfidf): 			# 下标idx = index
    lt = []
    # 将query由稀疏矩阵转为普通矩阵,并取其第1行,此处目的是将其转为一维矩阵。
    query = query.toarray()[0]  				# 其实query二维矩阵只有一行
    for q in q_tfidf:
        q = q.toarray()        				# 将q由稀疏矩阵转换为普通矩阵
        num = float(np.matmul(q, query))    	# 计算矩阵的点积
        denom = np.linalg.norm(q) * np.linalg.norm(query)	
        if denom == 0:
            cos = 0.0
        else:
            cos = num / denom				# 规范化,denom分母
        lt.append(cos)
    best_idx = lt.index(max(lt))
    return best_idx						# 返回值是与查询语句最相似的问题下标
np.linalg.norm(q)是问题向量的长度:

>>> np.linalg.norm([1, 3, 2])

3.7416573867739413

上述代码计算了的值

np.linalg.norm(q)是查询向量的长度

三,完整代码

python 复制代码
import jieba
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer

def read_corpus(file):
    lt = []
    with open(file, 'r', encoding='utf-8') as f:
        for line in f:
            lt.append(line.strip())
    return lt

def preprocess_text(q_list):
    lt = []
    for q in q_list:
        q = word_segment(q)
        lt.append(q)
    return lt

# 度量查询query与问题库中各个问题的相似程度similarity
def idx_of_largest_sim(query, q_tfidf): # idx = index
    lt = []
    # 将query由稀疏矩阵转换为普通矩阵,并取其第1行
    query = query.toarray()[0]  
    for q in q_tfidf:
        q = q.toarray()         # 将q由稀疏矩阵转换为普通矩阵
        num = float(np.matmul(q, query))    # 计算矩阵的点积
        denom = np.linalg.norm(q) * np.linalg.norm(query)
        if denom == 0:
            cos = 0.0
        else:
            cos = num / denom
        lt.append(cos)
    best_idx = lt.index(max(lt))
    return best_idx

def calc_tfidf(q_list, ngram_range=(1, 1)):
    # 实例化一个tfidf对象
    vectorizer = TfidfVectorizer(min_df=1, norm='l2', \
                                 smooth_idf=True, \
                                 use_idf=True, \
                                 ngram_range=ngram_range)
    # 计算每个词的tfidf值
    features = vectorizer.fit_transform(q_list)
    return vectorizer, features

def convert2tfidf(q_list):
    vectorizer, q_tfidf = calc_tfidf(q_list)
    return vectorizer, q_tfidf

def word_segment(sentence):
    return ",".join(jieba.cut(sentence))

def answer(query):
    query = word_segment(query)
    query = vectorizer.transform([query])
    best_idx = idx_of_largest_sim(query, q_tfidf)
    return a_list[best_idx]

if __name__ == "__main__":
    q_list = read_corpus("questions.txt")    # 问题列表
    a_list = read_corpus("answers.txt")      # 答案列表
    # 分词后的问题列表,每个问题的分词字符串为一个列表元素
    q_list = preprocess_text(q_list)
    vectorizer, q_tfidf = convert2tfidf(q_list)
    
    flag = True
    while flag:
        print("\n请输入查询,输入结束后按回车键:")
        query = input()
        if query.lower() == 'q':
            break
        print("正在为您查询,请稍后!")
        print("查询结果:", answer(query), sep="")
相关推荐
SelectDB技术团队2 分钟前
Apache Doris 2025 Roadmap:构建 GenAI 时代实时高效统一的数据底座
大数据·数据库·数据仓库·人工智能·ai·数据分析·湖仓一体
weixin_435208162 分钟前
通过 Markdown 改进 RAG 文档处理
人工智能·python·算法·自然语言处理·面试·nlp·aigc
大数据在线5 分钟前
AI重塑云基础设施,亚马逊云科技打造AI定制版IaaS“样板房”
人工智能·云基础设施·ai大模型·亚马逊云科技
hello_ejb36 分钟前
聊聊Spring AI的RetrievalAugmentationAdvisor
人工智能·spring·restful
你觉得20521 分钟前
浙江大学朱霖潮研究员:《人工智能重塑科学与工程研究》以蛋白质结构预测为例|附PPT下载方法
大数据·人工智能·机器学习·ai·云计算·aigc·powerpoint
人工干智能42 分钟前
科普:One-Class SVM和SVDD
人工智能·机器学习·支持向量机
蚝油菜花1 小时前
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
人工智能·开源
蚝油菜花1 小时前
PaperBench:OpenAI开源AI智能体评测基准,8316节点精准考核复现能力
人工智能·开源
蚝油菜花1 小时前
DreamActor-M1:字节跳动推出AI动画黑科技,静态照片秒变生动视频
人工智能·开源