TextRank算法学习笔记
Textrank的前身是PageRank,他啟發了TextRank,PageRank主要應用于對在線搜索中的網頁進行排序。PageRank 給每一個頁面一個正實數,值越高,越重要,在網絡搜索中的排序越靠前,把網頁看成一個節點,每一個鏈接看做一條邊,不斷迭代計算PageRank值,PageRank的計算公式如下
PR(Vi)=(1-d)+d*所有節點((i的前驅節點/i的后繼節點)的權值)之和
d是到達某頁面后用戶向后瀏覽的概率 1-d就是用戶停止瀏覽隨機跳到新的url的概率
為了保證平滑 應該將該公式中的1-d變成(1-d)/n否則會有不平滑項,如果有些網頁沒有跳出的鏈接則轉移到其它頁面的概率將是0 就不平滑了,所以要做出這樣的改變
假設網頁以等概率跳轉到任何網頁1/n,那么要么以概率d進行隨機跳轉或者1-d進行跳轉的初始概率都是1/n 所有的網頁被訪問的概率都相同,經歷過迭代以后,PR值會趨近與收斂。
TextRank算法和PageRank算法的相似的地方有三個:
用句子代替網頁
把任意兩個句子的相似性看做網頁跳轉的概率
相似性的分存儲在一個方形矩陣中
因為不同句子的相似度不同,所以初始的概率并不一致
TextRank的流程
Text 變成 Sentence (句子)變成vector (向量)變成Similarity Matrix(相似度矩陣)再變成Sentence Ranking(句子 排序)最后變成Summary(摘要)
下面是一段從網上抄的代碼鏈接是:TextRank算法詳細講解與代碼實現(完整) - 方格田 - 博客園 ?https://www.cnblogs.com/motohq/p/11887420.html
第一步是request爬一篇文章
import?requests from?lxml import?html etree=html.etree url='http://news.12371.cn/2013/01/28/ARTI1359357184590944.shtml'?data=requests.get(url)
data.encoding='utf-8'?#print(data)?
s=etree.HTML(data.text)
text1=s.xpath('//*[@id="font_area"]/p/text()')#得到的文本是一個列表,里面有6項,代表6個自然段?
title=s.xpath('/html/head/title/text()')[0].strip()#[0]是取標題的第一項,trip()去掉首尾空格
?print("爬取文本:\n","標題:",title,"\n正文:",text1) text=""?# 將得到的文本寫入文件
?for?i in?range(0,len(text1)-1): text+=text1[i] sentence_list=[] print(text) title=title+'.txt'?with?open(title, 'w', encoding='utf-8') as?f: f.writelines(text)
第二步是打開爬好的文章
import?numpy as?np
import?re,jieba from?itertools import?chain #打開文件?
sentences_list = [] file_path='吳邦國重申:中國堅持和平發展道路不會因國力地位變化而改變.txt'?fp = open(file_path,'r',encoding="utf8") for?line in?fp.readlines(): if?line.strip(): # 把元素按照[。!;?]進行分隔,得到句子。?
line_split = re.split(r'[。!;?]',line.strip()) # [。!;?]這些符號也會劃分出來,把它們去掉。?
line_split = [line.strip() for?line in?line_split if?line.strip() not?in?['。','!','?',';'] and?len(line.strip())>1] sentences_list.append(line_split) sentences_list = list(chain.from_iterable(sentences_list)) print("前10個句子為:\n") print(sentences_list[:10]) print("句子總數:", len(sentences_list))
第三步是分詞,從網上下載一個停詞文本,當遇到這個文本中的詞時就被劃分成一個新詞。
#加載停用詞?stoplist= [word.strip() for?word in?open('stopwords.txt',encoding='utf-8').readlines()] # print(stoplist)?# 對句子進行分詞?
def?seg_depart(sentence):?# 去掉非漢字字符?
sentence = re.sub(r'[^\u4e00-\u9fa5]+','',sentence) sentence_depart = jieba.cut(sentence.strip()) word_list = [] for?word in?sentence_depart: if?word not?in?stoplist: word_list.append(word) # 如果句子整個被過濾掉了,如:'02-2717:56'被過濾,那就返回[],保持句子的數量不變?
return?word_list sentence_word_list = [] for?sentence in?sentences_list: line_seg = seg_depart(sentence) sentence_word_list.append(line_seg) print("一共有",len(sentences_list),'個句子。\n') print("前10個句子分詞后的結果為:\n",sentence_word_list[:10]) # 保證處理后句子的數量不變,我們后面才好根據textrank值取出未處理之前的句子作為摘要。
?if?len(sentences_list) == len(sentence_word_list): print("\n數據預處理后句子的數量不變!")
輸出:
Building?prefix?dict?from?the?default?dictionary?...Loading?model?from?cache?C:\Users\To\AppData\Local\Temp\jieba.cacheLoading?model?cost?0.990?seconds.Prefix?dict?has?been?built?succesfully.
一共有 19 個句子。
前10個句子分詞后的結果為:
?[['亞太地區', '影響', '議會', '間', '組織', '亞太', '議會', '論壇', '日召', '符拉迪沃斯托克', '年會'], ['中國', '全國人大常委會', '委員長', '吳邦國', '與會', '發言', '中', '重申', '和平', '發展', '道路', '中國', '時代', '發展', '潮流', '根本利益', '作出', '戰略', '抉擇', '綜合國力', '國際', '地位', '變化', '改變'], ['亞太', '議會', '論壇', '成立', '擁有', '中國', '俄羅斯', '美國', '成員國'], ['年會', '論壇', '決策機構', '輪流', '太平洋', '兩岸'], ['本屆', '年會', '為期', '天', '與會代表', '圍繞', '地區', '經濟', '貿易', '區域合作', '議題', '坦誠', '對話'], ['吳邦國', '主旨', '發言', '中', '闡述', '中方', '事關', '亞太地區', '和平', '發展', '原則'], ['指出', '亞太地區', '和平', '合作', '發展', '亞太', '各國', '責任', '各方', '戰略', '高度', '審視', '地區', '形勢', '關系', '努力', '共識', '付諸行動'], ['摒棄', '冷戰', '思維', '博弈', '觀念', '相互尊重', '主權', '核心', '利益', '推動', '建立', '公平', '地區', '機制'], ['推動', '高新技術', '先進', '制造', '節能', '環保', '能源', '資源', '現代農業', '領域', '務實', '合作', '反對', '形式', '保護主義', '推動', '貿易', '投資', '自由化', '區域', '經濟', '一體化'], ['尊重', '文明', '多樣性', '尊重', '各國', '自主', '選擇', '發展', '道路', '文明', '社會制度', '相互', '交流', '借鑒', '推動', '亞太', '多元', '文明', '共同進步']]
數據預處理后句子的數量不變!
4.利用word2vec生成詞向量
Word2Vec之類的模型,準確來說應該是“自監督”的,它事實上訓練了一個語言模型,通過語言模型來獲取詞向量。
所謂語言模型,就是通過前個字預測下一個字的概率,就是一個多分類器而已,我們輸入one hot,然后連接一個全連接層,然后再連接若干個層,最后接一個softmax分類器,就可以得到語言模型了,然后將大批量文本輸入訓練就行了,最后得到第一個全連接層的參數,就是字、詞向量表,當然,Word2Vec還做了大量的簡化,但是那都是在語言模型本身做的簡化,它的第一層還是全連接層,全連接層的參數就是字、詞向量表。
#求句子最大長度
maxLen=0for?sentence in?sentences_list:
????length=0
????for?wd in?sentence:
????????length=length+1
????if?(length>maxLen):maxLen=length
#fit_on_texts函數可以將輸入的文本中的每個詞編號,#編號是根據詞頻的,詞頻越大,編號越小from?keras.preprocessing.text import?Tokenizer
tokenizer=Tokenizer()
tokenizer.fit_on_texts(sentence_word_list)
vocab = tokenizer.word_index ?# 得到每個詞的編號
print(vocab)
輸出:
{'發展': 1, '中國': 2, '議會': 3, '和平': 4, '推動': 5, '亞太': 6, '吳邦國': 7, '戰略': 8, '國家': 9, '亞太地區': 10, '論壇': 11, '年會': 12, '中': 13, '道路': 14, '地區': 15, '努力': 16, '領域': 17, '文明': 18, '間': 19, '發言': 20, '時代': 21, '潮流': 22,'根本利益': 23, '作出': 24, '抉擇': 25, '綜合國力': 26, '國際': 27, '地位': 28, '變化': 29,'改變': 30, '經濟': 31, '貿易': 32, '對話': 33, '合作': 34, '各國': 35, '關系': 36,'主權': 37, '尊重': 38, '交流': 39, '發揮': 40, '作用': 41, '互利': 42, '外交政策': 43,
?'對外開放': 44, '解決': 45, '始終不渝': 46, '奉行': 47, '影響': 48, '組織': 49,
?'日召': 50, '符拉迪沃斯托克': 51, '全國人大常委會': 52, '委員長': 53, '與會': 54,'重申': 55, '成立': 56, '擁有': 57, '俄羅斯': 58, '美國': 59, '成員國': 60,
?'決策機構': 61, '輪流': 62, '太平洋': 63, '兩岸': 64, '本屆': 65, '為期': 66,'天': 67, '與會代表': 68, '圍繞': 69, '區域合作': 70, '議題': 71, '坦誠': 72, '主旨': 73, '闡述': 74, '中方': 75, '事關': 76, '原則': 77, '指出': 78, '責任': 79,'各方': 80, '高度': 81, '審視': 82, '形勢': 83, '共識': 84, '付諸行動': 85,'摒棄': 86, '冷戰': 87, '思維': 88, '博弈': 89, '觀念': 90, '相互尊重': 91, '核心': 92, '利益': 93, '建立': 94, '公平': 95, '機制': 96, '高新技術': 97,
?'先進': 98, '制造': 99, '節能': 100, '環保': 101, '能源': 102, '資源': 103, '現代農業': 104, '務實': 105, '反對': 106, '形式': 107, '保護主義': 108,'投資': 109, '自由化': 110, '區域': 111, '一體化': 112, '多樣性': 113, '自主': 114,'選擇': 115, '社會制度': 116, '相互': 117, '借鑒': 118, '多元': 119, '共同進步': 120,
?'政治': 121, '生活': 122, '成員': 123, '應': 124, '敦促': 125, '支持': 126, '本國': 127,
?'政府': 128, '實施': 129, '有利于': 130, '贏': 131, '各層次': 132, '交往': 133,
?'建設性': 134, '力量': 135, '推進': 136, '成就': 137, '舉世矚目': 138, '面臨': 139,
?'矛盾': 140, '挑戰': 141, '世所': 142, '罕見': 143, '關鍵': 144, '一心一意': 145,
?'謀發展': 146, '共贏': 147, '開放': 148, '廣': 149, '高層次': 150, '走': 151, '堅定': 152,
?'獨立自主': 153, '這是': 154, '大小': 155, '強弱': 156, '貧富': 157, '一律平等': 158,
?'干涉': 159, '別國': 160, '內政': 161, '永不': 162, '稱霸': 163, '和平談判': 164,
?'方式': 165, '周邊': 166, '鄰國': 167, '歷史': 168, '遺留': 169, '陸地': 170,
?'邊界問題': 171, '妥善處理': 172, '島嶼': 173, '海洋權益': 174, '爭端': 175,
?'和平解決': 176, '國際爭端': 177, '熱點問題': 178, '負責': 179, '大國': 180}
簡要介紹一下word2vec模型參數含義
sentences: 我們要分析的語料,可以是一個列表,或者從文件中遍歷讀出。后面我們會有從文件讀出的例子。
size: 詞向量的維度,默認值是100。這個維度的取值一般與我們的語料的大小相關,如果是不大的語料,比如小于100M的文本語料,則使用默認值一般就可以了。如果是超大的語料,建議增大維度。
window:即詞向量上下文最大距離,這個參數在我們的算法原理篇中標記為c,window越大,則和某一詞較遠的詞也會產生上下文關系。默認值為5。在實際使用中,可以根據實際的需求來動態調整這個window的大小。如果是小語料則這個值可以設的更小。對于一般的語料這個值推薦在[5,10]之間。
sg: 即我們的word2vec兩個模型的選擇了。如果是0, 則是CBOW模型,是1則是Skip-Gram模型,默認是0即CBOW模型。
hs: 即我們的word2vec兩個解法的選擇了,如果是0, 則是Negative Sampling,是1的話并且負采樣個數negative大于0, 則是Hierarchical Softmax。默認是0即Negative Sampling。
negative:即使用Negative Sampling時負采樣的個數,默認是5。推薦在[3,10]之間。這個參數在我們的算法原理篇中標記為neg。
cbow_mean: 僅用于CBOW在做投影的時候,為0,則算法中的xw為上下文的詞向量之和,為1則為上下文的詞向量的平均值。在我們的原理篇中,是按照詞向量的平均值來描述的。個人比較喜歡用平均值來表示xw,默認值也是1,不推薦修改默認值。
min_count:需要計算詞向量的最小詞頻。這個值可以去掉一些很生僻的低頻詞,默認是5。如果是小語料,可以調低這個值。
iter: 隨機梯度下降法中迭代的最大次數,默認是5。對于大語料,可以增大這個值。
alpha: 在隨機梯度下降法中迭代的初始步長。算法原理篇中標記為η,默認是0.025。
min_alpha: 由于算法支持在迭代的過程中逐漸減小步長,min_alpha給出了最小的迭代步長值。隨機梯度下降中每輪的迭代步長可以由iter,alpha, min_alpha一起得出。這部分由于不是word2vec算法的核心內容,因此在原理篇我們沒有提到。對于大語料,需要對alpha, min_alpha,iter一起調參,來選擇合適的三個值。
word2vec的訓練:
# 設置詞語向量維度
num_featrues = 300# 保證被考慮詞語的最低頻度,對于小語料,設置為1才可能能輸出所有的詞,因為有的詞可能在每個句子中只出現一次
min_word_count = 1# 設置并行化訓練使用CPU計算核心數量
num_workers =4# 設置詞語上下文窗口大小
context = 5#開始訓練
model = word2vec.Word2Vec(sentence_word_list, workers=num_workers, size=num_featrues, min_count=min_word_count, window=context)
model.init_sims(replace=True)
'''
# 如果有需要的話,可以輸入一個路徑,保存訓練好的模型
model.save("w2vModel1")
print(model)
#加載模型
model = word2vec.Word2Vec.load("w2vModel1")
'''
5.利用訓練后的word2vec自定義Embedding
word_embeddings = {}
count=0for?word, i in?vocab.items():
????try:
????????# model.wv[word]存的就是這個word的詞向量
????????word_embeddings[word] =model.wv[word]
????except?KeyError:
????????continue
print('輸出了:',count,'個詞')
6.得到詞語的embedding,用WordAVG作為句子的向量表示
sentence_vectors = []for?line in?sentence_word_list:
????if?len(line)!=0:
????????# 如果句子中的詞語不在字典中,那就把embedding設為300維元素為0的向量。
????????# 得到句子中全部詞的詞向量后,求平均值,得到句子的向量表示
????????#TypeError: type numpy.ndarray doesn't define __round__ method,將round改為np.round
????????v = np.round(sum(word_embeddings.get(word, np.zeros((300,))) for?word in?line)/(len(line)))
????else:
????????# 如果句子為[],那么就向量表示為300維元素為0個向量。
????????v = np.zeros((300,))
????sentence_vectors.append(v)
#計算句子之間的余弦相似度,構成相似度矩陣?
sim_mat = np.zeros([len(sentences_list), len(sentences_list)])
from?sklearn.metrics.pairwise import?cosine_similarity
for?i in?range(len(sentences_list)):
for?j in?range(len(sentences_list)):
if?i != j:
?sim_mat[i][j] = cosine_similarity(sentence_vectors[i].reshape(1,300), sentence_vectors[j].reshape(1,300))[0,0]
print("句子相似度矩陣的形狀為:",sim_mat.shape)
#迭代得到句子的textrank值,排序并取出摘要"""?import?networkx as?nx
# 利用句子相似度矩陣構建圖結構,句子為節點,句子相似度為轉移概率?nx_graph = nx.from_numpy_array(sim_mat)
# 得到所有句子的textrank值?scores = nx.pagerank(nx_graph)
# 根據textrank值對未處理的句子進行排序?ranked_sentences = sorted(((scores[i],s) for?i,s in?enumerate(sentences_list)), reverse=True)
# 取出得分最高的前3個句子作為摘要?sn = 3?for?i in?range(sn): print("第"+str(i+1)+"條摘要:\n\n",ranked_sentences[i][1],'\n')
總結
以上是生活随笔為你收集整理的TextRank算法学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LC152---乘积最大子数组
- 下一篇: Android 蓝牙 inquiry、i