赞
踩
该问答系统是基于已知的问题和其一一对应的答案进行实现的。首先需要准备两个文本文件,分别命名为“question.txt”和“answer.txt”,分别是问题文件和答案文件,每一行是一个问题以及对应的答案。
问题文件:
中国的首都是哪个城市?
今天气温多少度?
天津距离北京有多远?
小明正在干什么?
答案文件:
北京市
26度
135公里
在上课
- 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
执行结果:
>>> q_list = read_corpus("questions.txt")
>>> q_list
['中国的首都是哪个城市?', '今天气温多少度?', '天津距离北京有多远?', '小明正在干什么?']
>>> a_list = read_corpus("answers.txt")
>>> a_list
['北京市', '26度', '135公里', '在上课']
- 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()函数。
- 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
['中国,的,首都,是,哪个,城市,?', '今天,气温,多少度,?', '天津,距离,北京,有多远,?', '小明,正在,干什么,?']
- 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}
由上述可知,向量的第一个特征是“中国”,第二个特征是“今天”,第三个特征是“北京”,依次类推其他特征。
- 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)是查询向量的长度
- 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="")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。