智能阅读模型的构建(第六届泰迪杯C题)
項目描述:
構建智能閱讀模型主要通過兩個方法來實現,第一個是TF-IDF的變種——TFC-ICF,TFC-ICF較于TF-IDF是將一個問題的所有答案看成一個整體,類比于TF-IDF文本分類的文件夾,問題的每一個回答類比于TF-IDF的文件夾里的每個文檔。TFC是每個詞所在句子的頻率,叫類詞頻,ICF類比于逆文本率,叫倒類頻率。作為衡量每個詞在所有句子中的一個重要程度。利用sklearn里面的tfidfvectorizer先提取一個問題所對應的所有回答的特征詞向量,用這個特征詞向量,去和所有備選答案進行匹配和計算,最后得到一個TF-IDF值的矩陣,這個矩陣的行數是問題對應的備選答案的個數,列數就是特征詞向量里特征詞的個數。當對答案進行0、1判別時,先把問題分詞,將這些詞與每一句備選答案進行匹配,并把匹配到的詞的TFC-ICF的權值提取出來。一個回答里匹配到幾個詞就提取幾個權值,再把這些權值相加。這個相加的值作為該回答的得分。在下一步,設置閾值為0.31,哪句答案的得分大于等于0.31,這句答案的label判別為1,反之就判別為0。
第二個方法,首先構建了一個問題分類的特征詞表,把問題分為地點類,人名類,時間類、未知類。利用pyltp庫,對每個問題對應的所有答案,進行分詞、詞性標注、命名實體識別、句法依存分析、語義角色標注。流程就是:先將問題分詞之后,用前三種問題的特征詞向量判斷問題屬于這三種的哪一種,沒有匹配到就屬于第四種未知類,未知類的結果用第一種方法得到的結果來補充判斷。問題分類之后,如果判斷為地點類,就把答案的命名實體標注向量用re.match(‘S-Ns$’,word)判斷是否有地點的命名實體,有判斷label為1,無判斷label為0;如果問題為人名類,把答案的命名實體向量用re.match(‘S-Nh$’,word)判斷是否有人名的命名實體,有判斷label為1,無判斷label為0;如果判斷問題為時間類,就把答案的語義標注向量用re.match(‘TMP$’,word)判斷是否含有時間語義的詞語,有判斷label為1,無就判斷label為0。
最后將上述兩種方法分別得到的每個passage_id對應的label的值相加(這里選取第一種方法得到的label結果是通過設置閾值0.31進行判別后的, 其label值是0,1標記的),對每兩個相加得到的值判斷,大于等于1的值end_label標位1,小于1的值end_label標為0。
這個比賽因為組隊的兩個小伙伴臨時有事(準備托福雅思啥的)前期沒有參與進來,所以我 可以很自信得說:這比賽除了最后的文檔編寫從構思到代碼實現全是我這個組長完成的。最后獲得了一個三等獎,雖然有很多不甘心,因為它是按照參賽人數的比例來排序評獎,c題參賽的人數相對來說最少。
?
排序模型的代碼:
import json import jieba import pandas as pd import numpy as np import os import codecs import sys import re from sklearn.feature_extraction.text import CountVectorizer from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import confusion_matrix#導入計算混淆矩陣的庫 from imp import reload reload(sys) from tqdm import tqdm from sklearn.feature_extraction.text import TfidfVectorizers = codecs.open('longwang.txt','r',encoding = 'utf-16')def clean(text):#text = re.sub('[0-9]{2,}','',text)#消除兩位以上的數字#text= re.sub('(?:(?:\d+,?)+(?:\.?\d+)?)','',text)#消除數字text = text.replace(' ','')#消除空格#text = re.sub('http[s]?://(?:[a-z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-f][0-9a-f]))+','',text)#消除網頁鏈接text = re.sub('[a-zA-Z]','',text)#消除英文字母words = list(jieba.lcut(text))stopwords = [line.rstrip() for line in open('stopwords.txt','r',encoding="utf-8")]words_nostop = [w for w in words if w not in stopwords]return ' '.join(words_nostop)Sents = [line.rstrip('\r\n') for line in s]#/r/n 回車加換行 n = 2#設置兩行為一句話 raw_Sents = ['\r\n'.join(Sents[i:i+n]) for i in range(len(Sents)-n+1)]Sents = raw_SentsSents = [clean(i) for i in tqdm(iter(Sents))]#對每一句話進行清理from sklearn.feature_extraction.text import TfidfTransformer#導入計算tfidf的庫 from sklearn.feature_extraction.text import CountVectorizer#導入計算詞頻矩陣的庫corpu = Sents vectorizer=CountVectorizer()#該類會將文本中的詞語轉換為詞頻矩陣,矩陣元素a[i][j] 表示j詞在i類文本下的詞頻 transformer=TfidfTransformer()#該類會統計每個詞語的tf-idf權值 tfidf=transformer.fit_transform(vectorizer.fit_transform(corpu))#第一個fit_transform是計算tf-idf,第二個fit_transform是將文本轉為詞頻矩陣 word=vectorizer.get_feature_names()#獲取詞袋模型中的所有詞語 weight=tfidf.toarray()#將tf-idf矩陣抽取出來,元素a[i][j]表示j詞在i類文本中的tf-idf權重from collections import Counterdef search(s):result = {}answer = []score = []_ = jieba.lcut(s)for q in _:if q in word:for i in range(len(weight)):for j in range(len(word)):if q == word[j]:result[i] = result.get(i,0) + weight[i][j]result = Counter(result).most_common(10)for n in range(len(result)):answer.append(raw_Sents[result[n][0]])score.append(result[n][1])c = {"answer" : answer,"score" : score}tf = pd.DataFrame(c)return(tf)print (search(u'神級機甲有多強大'))''' #輸出結果:answer score 0 神級機甲師。在下不才,是傳靈學院機甲學院副院長、神級機甲師蒙特,特來請\r\n教 1.042843 1 神級機甲,那可是神級機甲啊,主動上門挑戰,丟了一臺神級機甲不說,還\r\n讓人家一個人就給擊退了。 1.026891 2 機甲被對方繳獲了,對方明顯沒有要把神級機甲還回來的意思。\r\n正在兩臺神級機甲內的機甲師不... 1.021547 3 但神級機甲對機甲師的保護是非常好的,他并沒有受傷,然后機甲就被人打\r\n開了。 1.020787 4 \r\n紅色機甲是什么?那可是神級機甲啊,機甲世界中的頂級機甲,號稱能夠以 0.988498 5 \r\n地朝著兩臺神級機甲打了過去。 0.987706 6 什么?”千古丈亭得到消息后,鼻子都快被氣歪了。\r\n神級機甲,那可是神級機甲啊,主動上門挑... 0.959375 7 在攻擊到來之前,他確實是被兩臺神級機甲護在了后面,可兩臺神級機甲也\r\n承受了最多的攻擊,... 0.923912 8 紅色機甲是什么?那可是神級機甲啊,機甲世界中的頂級機甲,號稱能夠以\r\n已之力改變戰爭格局... 0.877193 9 體積明顯要比其他顏色的機甲小一些,但誰都知道神級機甲有多強大,那可是和\r\n四字斗鎧比肩的... 0.876901 '''# In[76]:print (search(u'魔鬼群島的七位前輩')) ''' #輸出結果:answer score 0 你可知道,當初他也去過魔鬼群島,但是,他被魔鬼群島的七位前輩譽為自從有\r\n群島以后最難搞... 1.428616 1 乎所有人都喜歡他,這不是簡單的事情。這孩子性格溫和,但韌性十足。\r\n你可知道,當初他也去... 1.310614 2 聽到這句“玩得高興”,唐舞麟不禁打了個寒戰,不知道是內院的哪些學員\r\n在被他們折磨呢。七... 0.802956 3 當初,在魔鬼群島上,他用毅力忍受了毀滅之力帶來的痛苦,收獲最多,也\r\n開始找到了屬于自己的路。 0.646335 4 在被他們折磨呢。七位老魔自從來了這邊之后,那興奮勁比當初在魔鬼群島的時\r\n候增加了幾倍,... 0.626933 5 駱桂星忍不住道:“貪婪老….,…·老前輩,為什么當初在魔鬼群島,你們不是\r\n這樣給我們上... 0.592013 6 至連體重都沒有辦法控制,但他可以掌控自己的實力\r\n當初,在魔鬼群島上,他用毅力忍受了毀滅... 0.570836 7 激發年輕人的斗志,畢竟沒有什么能比初代史萊克七怪的傳奇更令人震撼了\r\n駱桂星忍不住道:“... 0.536613 8 乎沒有可行性的方法。\r\n貪夢老魔前輩,您有什么辦法嗎?” 0.444977 9 這實在是太可怕了。\r\n傳靈塔加上戰神殿,都湊不出七位極限斗羅。 0.416765 '''?
第二個通過命名實體識別和角色標注分類的方法:
# -*- coding: utf-8 -*- import json import jieba import pandas as pd import numpy as np import os import codecs import sys import re from pyltp import SentenceSplitter from pyltp import Segmentor from pyltp import Postagger from pyltp import SementicRoleLabeller from pyltp import NamedEntityRecognizer from pyltp import Parser# 導入用于分析的各種庫 import os LTP_DATA_DIR = '/root/Jupyter Notebook/TeddyCup/ltp_data_v3.4.0' # ltp模型目錄的路徑 cws_model_path = os.path.join(LTP_DATA_DIR, 'cws.model') # 分詞模型路徑,模型名稱為`cws.model` pos_model_path = os.path.join(LTP_DATA_DIR, 'pos.model') # 詞性標注模型路徑,模型名稱為`pos.model` ner_model_path = os.path.join(LTP_DATA_DIR, 'ner.model') # 命名實體識別模型路徑,模型名稱為`pos.model` par_model_path = os.path.join(LTP_DATA_DIR, 'parser.model') # 依存句法分析模型路徑,模型名稱為`parser.model` pisrl_model_path = os.path.join(LTP_DATA_DIR, 'pisrl.model') # 語義角色標注模型目錄路徑,模型目錄為`srl`。注意該模型路徑是一個目錄,而不是一個文件。# 分句函數 def segmentor(sentence):#分詞的輸入參數是句子segmentor = Segmentor() # 初始化實例segmentor.load(cws_model_path) # 加載模型words = segmentor.segment(sentence) # 分詞print ('\t'.join(words))words_list = list(words)segmentor.release() # 釋放模型return words_listsentence = '元芳你怎么看'#先將句子分詞 words = jieba.lcut(sentence)# 詞性標注的函數: def posttagger(words):#詞性標注輸入參數是列表postagger = Postagger() # 初始化實例postagger.load(pos_model_path) # 加載模型#words = ['元芳', '你', '怎么', '看'] # 分詞結果postags = postagger.postag(words) # 詞性標注#print ('\t'.join(postags))postagger.release() # 釋放模型return postags#命名實體識別函數 def ner(words, postags):#輸入的參數都是列表recognizer = NamedEntityRecognizer() # 初始化實例recognizer.load(ner_model_path) # 加載模型#words = ['元芳', '你', '怎么', '看']#postags = ['nh', 'r', 'r', 'v']netags = recognizer.recognize(words, postags) # 命名實體識別#print ('\t'.join(netags))recognizer.release() # 釋放模型return netags# 句法依存分析函數 def parse(words, postags):parser = Parser() # 初始化實例parser.load(par_model_path) # 加載模型#words = ['元芳', '你', '怎么', '看']#ostags = ['nh', 'r', 'r', 'v']arcs = parser.parse(words, postags) # 句法分析#print ("\t".join("%d:%s" % (arc.head, arc.relation) for arc in arcs))parser.release() # 釋放模型return arcs# 語義角色標注的函數: def role_label(words, postags, arcs):labeller = SementicRoleLabeller() # 初始化實例labeller.load(pisrl_model_path) # 加載模型#words = ['元芳', '你', '怎么', '看']#postags = ['nh', 'r', 'r', 'v']# arcs 使用依存句法分析的結果roles = labeller.label(words, postags, arcs) # 語義角色標注role_name = []# 打印結果#for role in roles:#print (role.index, "".join(#["%s:(%d,%d)" % (arg.name, arg.range.start, arg.range.end) for arg in role.arguments]))for role in roles:for arg in role.arguments:role_name.append(arg.name)labeller.release() # 釋放模型return role_name#命名實體識別的函數重新封裝 def mmst(a):b = jieba.lcut(a)c = posttagger(b)d = ner(b,c)g = []for i in d:g.append(i)#print(g)return gsss = mmst(sentence)#語義角色標注函數重新封裝 def jsbz(a):b = jieba.lcut(a)c = posttagger(b)d = parse(b,c)e = role_label(b,c,d)#print(e)return eb = jsbz(sentence)# 讀入json數據 file = codecs.open('test_data_sample.json','r',encoding='utf-8') #file = open(r"test_data_sample.json")f =file#把屬于同一個question的content組合在一起,根據不同的question分開,里面的建立一個字典 fileJson = json.load(f) a = len(fileJson) print(a) #label=[] #ct={} m = {}#內容的字典 passage_id = {} for i in range(a):field = fileJson[i]b = len(field['passages'])for j in range(b):h = []g = []g.append(field['passages'][j]['content'])h.append(0)m[i] = m.get(i,[]) + gpassage_id[i] = passage_id.get(i,[]) + h# 導入用于問句分類的特征詞:#導入地點類問題分類的特征詞 loc_words = [line.rstrip() for line in open('loc.txt','r',encoding = 'utf-8')]#導入人名類問題分類的特征詞 peo_words = [line.rstrip() for line in open('peo.txt','r',encoding = 'utf-8')]# 導入用于時間類問題分類的特征詞 tmp_words = [line.rstrip() for line in open('tmp.txt','r',encoding = 'utf-8')]# In[29]:#核心代碼 qs = {} score = [] a = len(fileJson) for i in range(a):field = fileJson[i]b = len(field['passages'])qs[i]= field['question']for j in range(b):s1 = mmst(m[i][j])s2 = jsbz(m[i][j])#命名實體標注print(s1)_ = jieba.lcut(qs[i])#對問題進行分詞print(_)for q in _:if q in loc_words:#對問題進分類,如果條件句為真,問題就分為地點類問題n =0for word in s1:if re.match('S-Ns$',word):#對回答中的n = n+1if n <=2 :passage_id[i][j] = 1print(1)for q in _:if q in peo_words:n =0for word in s1:if re.match('S-Nh$',word):n = n+1if n ==1 :passage_id[i][j] = 1print(2)for q in _:if q in tmp_words:n =0for word in s2:if re.match('TMP$',word):n = n+1if n <=2 :passage_id[i][j] = 1print(3)pid = []#將存放命名實體匹配模型得到的結果passage_id里面的0,1編號 g = []#將存放原數據的passage_id,像17148201這樣的# 將數據添加到列表里面 a = len(fileJson) for i in range(a):field = fileJson[i]b = len(field['passages'])for j in range(b):pid.append(passage_id[i][j])g.append(field['passages'][j]['passage_id'])c = {"label" : pid,"passage_id" : g} tf = pd.DataFrame(c) #tf['score'] = tf.score.apply(judge_score) #tf['label'] = tf.score.apply(judge_score)# 保存數據 tf.to_csv( 'pyltp_result_00001.csv', sep=',', escapechar='\\',index=False)#命名實體識別模型輸出的0,1label# 讀入數據 test_df = pd.read_csv("test_result_001.csv",encoding = 'utf-8',delimiter=",")#讀取前面tfc-icf模型計算的結果# 定義一個0 1 分類的函數 def judge_score1(x):if x >=0.31 :return 1else:return 0# 對數據框里面的數據 進行分類 test_df['score'] = test_df.score.apply(judge_score1)# 保存數據 test_df.to_csv( 'test_result_002.csv', sep=',', escapechar='\\',index=False)# 定義一個新的列表,將兩個方法的到的結果的值加起來 ppp = [] for i in range(len(tf.label)):ppp.append(tf.label[i]+test_df.score[i])# 定義第二個分類的函數 def judge_score2(x):if x >= 1:return 1else:return 0# 將列表轉化為數據框的形式 cccc = {"end_label" : ppp,"passage_id" : g} end_tf = pd.DataFrame(cccc) #tf['score'] = tf.score.apply(judge_score) end_tf['end_label'] = end_tf.end_label.apply(judge_score2)# 保存最后的結果 end_tf.to_csv( 'end_pyltp_result_00002.csv', sep=',', escapechar='\\',index=False)
?
?
總結
以上是生活随笔為你收集整理的智能阅读模型的构建(第六届泰迪杯C题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [置顶] 黑马程序员 --
- 下一篇: ETC/CFX/RVN/NEOXA/ER