搭建一个简单的问答系统

1 篇文章 0 订阅

学了很多什么分词,维特比,ui-gram之类的,但是能用起来才算真的学懂
三天的时间做完了这个项目 结果和想象不能说是完全一致 只能说是毫无关系

总结一下项目经验就是:
试试做个子数据集,要不然需要跑很久还不知道哪里错了
一步一步来想清楚步骤,一定是可以做出来的

好的我们开始复盘!

2.1第一部分: 读取文件,并把内容分别写到两个list里

import json
def read_corpus():
    """
    读取给定的语料库,并把问题列表和答案列表分别写入到 qlist, alist 里面。 在此过程中,不用对字符换做任何的处理(这部分需要在 Part 2.3里处理)
    qlist = ["问题1", “问题2”, “问题3” ....]
    alist = ["答案1", "答案2", "答案3" ....]
    务必要让每一个问题和答案对应起来(下标位置一致)
    """
    file="./data/train-v2.0.json"
    qlist=[]
    alist=[]
    k=0
    with open(file) as f:
        jsf=json.load(f)
        qadict=jsf['data']
        for i in qadict:
            qadict_para=i['paragraphs']
            for j in qadict_para:
                qadict_qas=j['qas']
                for m in qadict_qas:
                    qlist.append(m['question'])
                    k+=1
                    if m['answers']==[]:
                        alist.append([])
                    else:
                        alist.append(m['answers'][0]['text'])
    assert len(qlist) == len(alist)  # 确保长度一样
    return qlist, alist
qlist, alist=read_corpus()

2.2 理解数据(可视化分析/统计信息)

用到的是Counter计数器辅助包,可以把它当字典用,也顺带复习了对元组的操作

from collections import Counter

def count_word(list1):
    word_list=[]
    c=Counter()
    for q in list1:
    	try:#这边主要是alist那边有很多的[]空列表,不能执行split
            c.update(q.split())
        except:
            pass
    word_total=sum(c.values())#出现的单词数
    word_diff_total=len(c.keys())#不同的单词数

    return word_total,word_diff_total,c
import matplotlib.pyplot as plt
import numpy as np
word_total,word_diff_total,q_c=count_word(qlist)
a_word_total,a_word_diff_total,a_c=count_word(alist)

#拿到counter的value频率
list2=sorted(q_c.values(),reverse=True)
print(list2[:10])
plt.plot(list2[:100])

#找出最高频的前10个 most_common返回的是元组列表
#用了列表解析式q[0]返回的是元组的第一个元素
q_top10=q_c.most_common(10)
q_top10=[q[0] for q in q_top10]
print(q_top10)

2.3 文本预处理

在这步要学习如何去除标点,string.punctuation记录了所有的标点

import string
#1.设置停用词
from nltk.corpus import stopwords 
stop_words = set(stopwords.words('english')) 
low_frequency_words=[]
#4.建立低频词词典 上一步词频统计用处只有建立高频低频词典
for  key,value in q_c.items():
    if value<2:
        low_frequency_words.append(key)
#6.stemming
import nltk
porter = nltk.PorterStemmer()
# lancaster = nltk.LancasterStemmer() 都用的话会太慢
#辅助分词
from nltk.tokenize import word_tokenize 

def text_preprocessing(input_list):
   
    new_list = [] 
    for sentence in input_list:
        l_list = '' # 保存新的句子
        if sentence==[]:
            continue
        l=nltk.word_tokenize(sentence)

        for word in l:
            # 转换小写+stemming
            word = porter.stem(word)
#             word = lancaster.stem(word)
            
            # 3.去除所有标点符号
            word = ''.join(c for c in word if c not in string.punctuation)
#             punc = '~`!#$%^&*()_+-=|\';":/.,?><~·!@#¥%……&*()——+-=“:’;、。,?》《{}'
#             word=re.sub(r"[%s]+" %punc, "",word)
            
            # 5.处理数字
            if word.isdigit():
                word = word.replace(word,'#number')  ##也可以写为 re.sub(r'\d', "#number", l[i])
            
            if word not in stop_words and word not in low_frequency_words:
                l_list += word + ' '

        new_list.append(l_list)
            
    return new_list
       
qlist2 = text_preprocessing(qlist)   # 更新后的

2.4文本表示(文本转向量)

这步有三种tf-idf包

# TODO: 把qlist中的每一个问题字符串转换成tf-idf向量, 转换之后的结果存储在X矩阵里。 X的大小是: N* D的矩阵。 这里N是问题的个数(样本个数),
#       D是字典库的大小。 


from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer, TfidfTransformer

tfidf_vec = TfidfVectorizer() 
q_tfidf_matrix = tfidf_vec.fit_transform(qlist2)
q_tfidf_array=q_tfidf_matrix.toarray()

2.5 对于用户的输入问题,找到相似度最高的TOP5问题,并把5个潜在的答案做返回

def get_cos_similar_multi(v1: list, v2: list):
    num = np.dot([v1], np.array(v2).T)  # 向量点乘
    denom = np.linalg.norm(v1) * np.linalg.norm(v2, axis=1)  # 求模长的乘积
    res = num / denom
    res[np.isneginf(res)] = 0
    return 0.5 + 0.5 * res

def top5results(input_q):
    """
    给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
    1. 对于用户的输入 input_q 首先做一系列的预处理,然后再转换成tf-idf向量(利用上面的vectorizer)
    2. 计算跟每个库里的问题之间的相似度
    3. 找出相似度最高的top5问题的答案
    """
    
#     token=input_q.split()
#     print(token)
    tfidf_matrix = tfidf_vec.fit(qlist2).transform(input_q)
    tfidf_array=tfidf_matrix.toarray()
    
    res=get_cos_similar_multi(tfidf_array, q_tfidf_array)
    top_idxs=[x[0] for x in sorted(enumerate(res[0][0]), key=lambda x: x[1])[-5:]]
    return alist[top_idxs]

2.6利用倒排表的优化


# TODO: 基于倒排表的优化。在这里,我们可以定义一个类似于hash_map, 比如 inverted_index = {}, 然后存放包含每一个关键词的文档出现在了什么位置,
#       也就是,通过关键词的搜索首先来判断包含这些关键词的文档(比如出现至少一个),然后对于candidates问题做相似度比较。
# 
inverted_idx = {}  # 定一个一个简单的倒排表
high_frequency_words={}
def find_hf_words(dic):
    for key,value in dic.items():
        if value>10 and value<150:
            high_frequency_words[key]=[]
    return high_frequency_words

high_frequency_words=find_hf_words(q_c)

def create_rstable(qlist):
    for idx,q in enumerate(qlist):
        for word in q:
            if word in high_frequency_words:
                
                high_frequency_words[word].append(idx)
    return high_frequency_words
high_frequency_words = create_rstable(qlist)


def find_match(input_q):
    match_q=[]
    token=input_q.split()
    for t in token:
        if t in high_frequency_words:
            match_q+=high_frequency_words[t]
    return set(match_q)
match_q=find_match("Do you know I love you so much ?")
print(match_q)

def top5results_invidx(input_q):
    """
    给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
    1. 利用倒排表来筛选 candidate
    2. 对于用户的输入 input_q 首先做一系列的预处理,然后再转换成tf-idf向量(利用上面的vectorizer)
    3. 计算跟每个库里的问题之间的相似度
    4. 找出相似度最高的top5问题的答案
    
    """
        
#     token=input_q.split()
#     print(token)
    tfidf_matrix = tfidf_vec.fit(qlist2).transform(input_q)
    tfidf_array=tfidf_matrix.toarray()
    
    res=get_cos_similar_multi(tfidf_array, q_tfidf_array[list(match_q)])
    return res

2.7 基于词向量的文本表示

import numpy as np
with open('./data/glove.6B/glove.6B.100d.txt', 'r') as file1:
    emb = []
    vocab = []
    for line in file1.readlines():
        row = line.strip().replace("?",'').split(' ')
        vocab.append(row[0])#词表
        emb.append(row[1:])#词嵌入表
emb =np.asarray(emb)

#句子嵌入
import re
def sentence_embedding(sentence):
    glove_sentence=[0]*100
    for word in sentence.split():
        word=word.lower()
        punc = '~`!#$%^&*()_+-=|\';":/.,?><~·!@#¥%……&*()——+-=“:’;、。,?》《{}'
        word=re.sub(r"[%s]+" %punc, "",word)
        if word in vocab:
            glove_sentence+=emb[vocab.index(word)].astype(float)
    glove_sentence=glove_sentence/len(sentence.split())
    return glove_sentence
sentence_embedding("Do you know I love you so much ?")

#做qlist的嵌入表
def list_embedding(list1):
    glove_matrix = []
    for l in list1:
        glove_matrix.append(sentence_embedding(l))
    return glove_matrix
    
q_emb = list_embedding(qlist)

q_emb=np.array(q_emb)
def top5results_emb(input_q):
    """
    给定用户输入的问题 input_q, 返回最有可能的TOP 5问题。这里面需要做到以下几点:
    1. 利用倒排表来筛选 candidate
    2. 对于用户的输入 input_q,转换成句子向量
    3. 计算跟每个库里的问题之间的相似度
    4. 找出相似度最高的top5问题的答案
    """
    input_glove=sentence_embedding(input_q)
    match_q=find_match(input_q)
    res=get_cos_similar_multi(input_glove, q_emb[list(match_q)])
    return res

res=top5results_emb("Do you know I love you so much ?")
# print (top5results_emb(""))
top_idxs=[x[0] for x in sorted(enumerate(res[0]), key=lambda x: x[1])[-5:]]
print(top_idxs)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值