当前位置:   article > 正文

【自然语言处理】基于python的问答系统实现_智能问答系统 代码

智能问答系统 代码

一,文件准备

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

        问题文件:

                中国的首都是哪个城市?

                今天气温多少度?

                天津距离北京有多远?

                小明正在干什么?

        答案文件:

                北京市

                26度

                135公里

                在上课

二,实现原理

(1)导入模块

  1. import jieba
  2. import numpy as np
  3. from sklearn.feature_extraction.text import TfidfVectorizer

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

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

执行结果:

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

>>> q_list

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

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

>>> a_list

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

(3)分词

  1. def preprocess_text(q_list):
  2. lt = []
  3. for q in q_list:
  4. q = word_segment(q)
  5. lt.append(q)
  6. return lt

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

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

  1. def word_segment(sentence):
  2. 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向量化,计算每一个特征的权重

  1. def convert2tfidf(q_list):
  2. vectorizer, q_tfidf = calc_tfidf(q_list)
  3. return vectorizer, q_tfidf
  4. def calc_tfidf(q_list, ngram_range=(1, 1)):
  5. # 实例化一个tfidf对象
  6. vectorizer = TfidfVectorizer(min_df=1, norm='l2', \
  7. smooth_idf=True, \
  8. use_idf=True, \
  9. ngram_range=ngram_range)
  10. # 计算每个词的tfidf值
  11. features = vectorizer.fit_transform(q_list)
  12. 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)响应用户的“查询”

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

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

3.7416573867739413

上述代码计算了1的值

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

三,完整代码

  1. import jieba
  2. import numpy as np
  3. from sklearn.feature_extraction.text import TfidfVectorizer
  4. def read_corpus(file):
  5. lt = []
  6. with open(file, 'r', encoding='utf-8') as f:
  7. for line in f:
  8. lt.append(line.strip())
  9. return lt
  10. def preprocess_text(q_list):
  11. lt = []
  12. for q in q_list:
  13. q = word_segment(q)
  14. lt.append(q)
  15. return lt
  16. # 度量查询query与问题库中各个问题的相似程度similarity
  17. def idx_of_largest_sim(query, q_tfidf): # idx = index
  18. lt = []
  19. # 将query由稀疏矩阵转换为普通矩阵,并取其第1行
  20. query = query.toarray()[0]
  21. for q in q_tfidf:
  22. q = q.toarray() # 将q由稀疏矩阵转换为普通矩阵
  23. num = float(np.matmul(q, query)) # 计算矩阵的点积
  24. denom = np.linalg.norm(q) * np.linalg.norm(query)
  25. if denom == 0:
  26. cos = 0.0
  27. else:
  28. cos = num / denom
  29. lt.append(cos)
  30. best_idx = lt.index(max(lt))
  31. return best_idx
  32. def calc_tfidf(q_list, ngram_range=(1, 1)):
  33. # 实例化一个tfidf对象
  34. vectorizer = TfidfVectorizer(min_df=1, norm='l2', \
  35. smooth_idf=True, \
  36. use_idf=True, \
  37. ngram_range=ngram_range)
  38. # 计算每个词的tfidf值
  39. features = vectorizer.fit_transform(q_list)
  40. return vectorizer, features
  41. def convert2tfidf(q_list):
  42. vectorizer, q_tfidf = calc_tfidf(q_list)
  43. return vectorizer, q_tfidf
  44. def word_segment(sentence):
  45. return ",".join(jieba.cut(sentence))
  46. def answer(query):
  47. query = word_segment(query)
  48. query = vectorizer.transform([query])
  49. best_idx = idx_of_largest_sim(query, q_tfidf)
  50. return a_list[best_idx]
  51. if __name__ == "__main__":
  52. q_list = read_corpus("questions.txt") # 问题列表
  53. a_list = read_corpus("answers.txt") # 答案列表
  54. # 分词后的问题列表,每个问题的分词字符串为一个列表元素
  55. q_list = preprocess_text(q_list)
  56. vectorizer, q_tfidf = convert2tfidf(q_list)
  57. flag = True
  58. while flag:
  59. print("\n请输入查询,输入结束后按回车键:")
  60. query = input()
  61. if query.lower() == 'q':
  62. break
  63. print("正在为您查询,请稍后!")
  64. print("查询结果:", answer(query), sep="")

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/629629
推荐阅读
相关标签
  

闽ICP备14008679号