TextRank算法讲解与代码实现
參考文章:https://www.cnblogs.com/Luv-GEM/p/10884493.html
PageRank
在TextRank之前我們需要先了解一下PageRank算法。事實(shí)上它啟發(fā)了TextRank!PageRank主要用于對在線搜索結(jié)果中的網(wǎng)頁進(jìn)行排序。
PageRank對于每個網(wǎng)頁頁面都給出一個正實(shí)數(shù),表示網(wǎng)頁的重要程度,PageRank值越高,表示網(wǎng)頁越重要,在互聯(lián)網(wǎng)搜索的排序中越可能被排在前面。
假設(shè)整個互聯(lián)網(wǎng)是一個有向圖,節(jié)點(diǎn)是網(wǎng)頁,每條邊是轉(zhuǎn)移概率。網(wǎng)頁瀏覽者在每個頁面上依照連接出去的超鏈接,以等概率跳轉(zhuǎn)到下一個網(wǎng)頁,并且在網(wǎng)頁上持續(xù)不斷地進(jìn)行這樣的隨機(jī)跳轉(zhuǎn),這個過程形成了一階馬爾科夫鏈,比如下圖:
每個笑臉是一個網(wǎng)頁,既有其他網(wǎng)頁跳轉(zhuǎn)到該網(wǎng)頁,該網(wǎng)頁也會跳轉(zhuǎn)到其他網(wǎng)頁。在不斷地跳轉(zhuǎn)之后,這個馬爾科夫鏈會形成一個平穩(wěn)分布,而PageRank就是這個平穩(wěn)分布,每個網(wǎng)頁的PageRank值就是平穩(wěn)概率。
PageRank的核心公式是PageRank值的計算公式。這個公式來自于《統(tǒng)計學(xué)習(xí)方法》,等號右邊的平滑項(xiàng)(通過某種處理,避免一些突變的畸形值,盡可能接近實(shí)際情況)不是(1-d),而是(1-d)/n。
阻尼系數(shù)d的意義是,在任意時刻,用戶到達(dá)某頁面后并繼續(xù)向后瀏覽的概率。1-d就是用戶停止點(diǎn)擊,隨機(jī)跳到新URL的概率。
加平滑項(xiàng)是因?yàn)橛行┚W(wǎng)頁沒有跳出去的鏈接,那么轉(zhuǎn)移到其他網(wǎng)頁的概率將會是0,這樣就無法保證存在馬爾科夫鏈的平穩(wěn)分布。
于是,我們假設(shè)網(wǎng)頁以等概率(1/n)跳轉(zhuǎn)到任何網(wǎng)頁,再按照阻尼系數(shù)d,對這個等概率(1/n)與存在鏈接的網(wǎng)頁的轉(zhuǎn)移概率進(jìn)行線性組合,那么馬爾科夫鏈一定存在平穩(wěn)分布,一定可以得到網(wǎng)頁的PageRank值。
所以PageRank的定義意味著網(wǎng)頁瀏覽者按照以下方式在網(wǎng)上隨機(jī)游走:以概率d按照存在的超鏈接隨機(jī)跳轉(zhuǎn),以等概率從超鏈接跳轉(zhuǎn)到下一個頁面;或以概率(1-d)進(jìn)行完全隨機(jī)跳轉(zhuǎn),這時以等概率(1/n)跳轉(zhuǎn)到任意網(wǎng)頁。
PageRank的計算是一個迭代過程,先假設(shè)一個初始的PageRank分布,通過迭代,不斷計算所有網(wǎng)頁的PageRank值,直到收斂為止,也就是:
這篇文章里有詳細(xì)的例子:https://www.cnblogs.com/cuiyubo/p/10175268.html
TextRank
兩種算法的相似之處:
- 用句子代替網(wǎng)頁
- 任意兩個句子的相似性等價于網(wǎng)頁轉(zhuǎn)換概率
- 相似性得分存儲在一個方形矩陣中,類似于PageRank的矩陣M
不過公式有些小的差別,那就是用句子的相似度類比于網(wǎng)頁轉(zhuǎn)移概率,用歸一化的句子相似度代替了PageRank中相等的轉(zhuǎn)移概率,這意味著在TextRank中,所有節(jié)點(diǎn)的轉(zhuǎn)移概率不會完全相等。
TextRank算法是一種抽取式的無監(jiān)督的文本摘要方法。讓我們看一下我們將遵循的TextRank算法的流程:
代碼實(shí)現(xiàn)
1.爬取中國黨員網(wǎng)上一篇文章并保存
import requests from lxml import htmletree=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項(xiàng),代表6個自然段 title=s.xpath('/html/head/title/text()')[0].strip()#[0]是取標(biāo)題的第一項(xiàng),trip()去掉首尾空格 print("爬取文本:\n","標(biāo)題:",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)2.打開文件:
import numpy as np import re,jieba from itertools import chain#打開文件 sentences_list = [] file_path='吳邦國重申:中國堅(jiān)持和平發(fā)展道路不會因國力地位變化而改變_黨建_共產(chǎn)黨員網(wǎng).txt' fp = open(file_path,'r',encoding="utf8") for line in fp.readlines():if line.strip():# 把元素按照[。!;?]進(jìn)行分隔,得到句子。line_split = re.split(r'[。!;?]',line.strip())# [。!;?]這些符號也會劃分出來,把它們?nèi)サ簟?/span>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("句子總數(shù):", len(sentences_list))輸出:
前10個句子為:['亞太地區(qū)影響最大的議會間組織——亞太議會論壇28日召在符拉迪沃斯托克召開年會', '中國全國人大常委會委員長吳邦國在與會發(fā)言中重申,堅(jiān)持和平發(fā)展道路是中國基于時代發(fā)展潮流和自身根本利益作出的戰(zhàn)略抉擇,不會因?yàn)榫C合國力和國際地位的變化而改變', '亞太議會論壇成立于1993年,擁有中國、俄羅斯、美國等27個成員國', '年會是這個論壇的最高決策機(jī)構(gòu),每年輪流在太平洋兩岸舉行', '據(jù)了解,本屆年會為期3天,與會代表將圍繞地區(qū)安全、經(jīng)濟(jì)貿(mào)易、區(qū)域合作等議題進(jìn)行坦誠對話', '吳邦國在年會主旨發(fā)言中闡述了中方在事關(guān)亞太地區(qū)和平發(fā)展重大問題上的原則主張', '他指出,促進(jìn)亞太地區(qū)和平合作發(fā)展,是亞太各國的共同責(zé)任,各方要從戰(zhàn)略高度審視地區(qū)形勢和彼此關(guān)系,努力擴(kuò)大共識、付諸行動', '“我們要摒棄冷戰(zhàn)思維和零和博弈觀念,相互尊重彼此主權(quán)和核心利益,推動建立公平有效的地區(qū)安全機(jī)制', '要積極推動高新技術(shù)、先進(jìn)制造、節(jié)能環(huán)保、能源資源、現(xiàn)代農(nóng)業(yè)等領(lǐng)域務(wù)實(shí)合作,反對各種形式的保護(hù)主義,推動貿(mào)易和投資自由化、區(qū)域經(jīng)濟(jì)一體化', '要尊重文明多樣性,尊重各國人民自主選擇的發(fā)展道路,促進(jìn)不同文明和社會制度相互交流借鑒,推動亞太多元文明共同進(jìn)步'] 句子總數(shù): 193.分詞,這里的停用詞用的網(wǎng)上的,很容易搜到
#加載停用詞 stoplist= [word.strip() for word in open('stopwords.txt',encoding='utf-8').readlines()] # print(stoplist)# 對句子進(jìn)行分詞 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'被過濾,那就返回[],保持句子的數(shù)量不變return word_listsentence_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個句子分詞后的結(jié)果為:\n",sentence_word_list[:10])# 保證處理后句子的數(shù)量不變,我們后面才好根據(jù)textrank值取出未處理之前的句子作為摘要。 if len(sentences_list) == len(sentence_word_list):print("\n數(shù)據(jù)預(yù)處理后句子的數(shù)量不變!")輸出:
Building prefix dict from the default dictionary ... Loading model from cache C:\Users\To\AppData\Local\Temp\jieba.cache Loading model cost 0.990 seconds. Prefix dict has been built succesfully. 一共有 19 個句子。前10個句子分詞后的結(jié)果為:[['亞太地區(qū)', '影響', '議會', '間', '組織', '亞太', '議會', '論壇', '日召', '符拉迪沃斯托克', '年會'], ['中國', '全國人大常委會', '委員長', '吳邦國', '與會', '發(fā)言', '中', '重申', '和平', '發(fā)展', '道路', '中國', '時代', '發(fā)展', '潮流', '根本利益', '作出', '戰(zhàn)略', '抉擇', '綜合國力', '國際', '地位', '變化', '改變'], ['亞太', '議會', '論壇', '成立', '擁有', '中國', '俄羅斯', '美國', '成員國'], ['年會', '論壇', '決策機(jī)構(gòu)', '輪流', '太平洋', '兩岸'], ['本屆', '年會', '為期', '天', '與會代表', '圍繞', '地區(qū)', '經(jīng)濟(jì)', '貿(mào)易', '區(qū)域合作', '議題', '坦誠', '對話'], ['吳邦國', '主旨', '發(fā)言', '中', '闡述', '中方', '事關(guān)', '亞太地區(qū)', '和平', '發(fā)展', '原則'], ['指出', '亞太地區(qū)', '和平', '合作', '發(fā)展', '亞太', '各國', '責(zé)任', '各方', '戰(zhàn)略', '高度', '審視', '地區(qū)', '形勢', '關(guān)系', '努力', '共識', '付諸行動'], ['摒棄', '冷戰(zhàn)', '思維', '博弈', '觀念', '相互尊重', '主權(quán)', '核心', '利益', '推動', '建立', '公平', '地區(qū)', '機(jī)制'], ['推動', '高新技術(shù)', '先進(jìn)', '制造', '節(jié)能', '環(huán)保', '能源', '資源', '現(xiàn)代農(nóng)業(yè)', '領(lǐng)域', '務(wù)實(shí)', '合作', '反對', '形式', '保護(hù)主義', '推動', '貿(mào)易', '投資', '自由化', '區(qū)域', '經(jīng)濟(jì)', '一體化'], ['尊重', '文明', '多樣性', '尊重', '各國', '自主', '選擇', '發(fā)展', '道路', '文明', '社會制度', '相互', '交流', '借鑒', '推動', '亞太', '多元', '文明', '共同進(jìn)步']]數(shù)據(jù)預(yù)處理后句子的數(shù)量不變!4.利用word2vec生成詞向量
Word2Vec之類的模型,準(zhǔn)確來說應(yīng)該是“自監(jiān)督”的,它事實(shí)上訓(xùn)練了一個語言模型,通過語言模型來獲取詞向量。
所謂語言模型,就是通過前個字預(yù)測下一個字的概率,就是一個多分類器而已,我們輸入one hot,然后連接一個全連接層,然后再連接若干個層,最后接一個softmax分類器,就可以得到語言模型了,然后將大批量文本輸入訓(xùn)練就行了,最后得到第一個全連接層的參數(shù),就是字、詞向量表,當(dāng)然,Word2Vec還做了大量的簡化,但是那都是在語言模型本身做的簡化,它的第一層還是全連接層,全連接層的參數(shù)就是字、詞向量表。
輸出:
{'發(fā)展': 1, '中國': 2, '議會': 3, '和平': 4, '推動': 5, '亞太': 6, '吳邦國': 7, '戰(zhàn)略': 8, '國家': 9, '亞太地區(qū)': 10, '論壇': 11, '年會': 12, '中': 13, '道路': 14, '地區(qū)': 15, '努力': 16, '領(lǐng)域': 17, '文明': 18, '間': 19, '發(fā)言': 20, '時代': 21, '潮流': 22, '根本利益': 23, '作出': 24, '抉擇': 25, '綜合國力': 26, '國際': 27, '地位': 28, '變化': 29, '改變': 30, '經(jīng)濟(jì)': 31, '貿(mào)易': 32, '對話': 33, '合作': 34, '各國': 35, '關(guān)系': 36, '主權(quán)': 37, '尊重': 38, '交流': 39, '發(fā)揮': 40, '作用': 41, '互利': 42, '外交政策': 43,'對外開放': 44, '解決': 45, '始終不渝': 46, '奉行': 47, '影響': 48, '組織': 49, '日召': 50, '符拉迪沃斯托克': 51, '全國人大常委會': 52, '委員長': 53, '與會': 54, '重申': 55, '成立': 56, '擁有': 57, '俄羅斯': 58, '美國': 59, '成員國': 60,'決策機(jī)構(gòu)': 61, '輪流': 62, '太平洋': 63, '兩岸': 64, '本屆': 65, '為期': 66, '天': 67, '與會代表': 68, '圍繞': 69, '區(qū)域合作': 70, '議題': 71, '坦誠': 72, '主旨': 73, '闡述': 74, '中方': 75, '事關(guān)': 76, '原則': 77, '指出': 78, '責(zé)任': 79, '各方': 80, '高度': 81, '審視': 82, '形勢': 83, '共識': 84, '付諸行動': 85, '摒棄': 86, '冷戰(zhàn)': 87, '思維': 88, '博弈': 89, '觀念': 90, '相互尊重': 91, '核心': 92, '利益': 93, '建立': 94, '公平': 95, '機(jī)制': 96, '高新技術(shù)': 97, '先進(jìn)': 98, '制造': 99, '節(jié)能': 100, '環(huán)保': 101, '能源': 102, '資源': 103, '現(xiàn)代農(nóng)業(yè)': 104, '務(wù)實(shí)': 105, '反對': 106, '形式': 107, '保護(hù)主義': 108, '投資': 109, '自由化': 110, '區(qū)域': 111, '一體化': 112, '多樣性': 113, '自主': 114, '選擇': 115, '社會制度': 116, '相互': 117, '借鑒': 118, '多元': 119, '共同進(jìn)步': 120,'政治': 121, '生活': 122, '成員': 123, '應(yīng)': 124, '敦促': 125, '支持': 126, '本國': 127, '政府': 128, '實(shí)施': 129, '有利于': 130, '贏': 131, '各層次': 132, '交往': 133, '建設(shè)性': 134, '力量': 135, '推進(jìn)': 136, '成就': 137, '舉世矚目': 138, '面臨': 139, '矛盾': 140, '挑戰(zhàn)': 141, '世所': 142, '罕見': 143, '關(guān)鍵': 144, '一心一意': 145, '謀發(fā)展': 146, '共贏': 147, '開放': 148, '廣': 149, '高層次': 150, '走': 151, '堅(jiān)定': 152, '獨(dú)立自主': 153, '這是': 154, '大小': 155, '強(qiáng)弱': 156, '貧富': 157, '一律平等': 158, '干涉': 159, '別國': 160, '內(nèi)政': 161, '永不': 162, '稱霸': 163, '和平談判': 164, '方式': 165, '周邊': 166, '鄰國': 167, '歷史': 168, '遺留': 169, '陸地': 170, '邊界問題': 171, '妥善處理': 172, '島嶼': 173, '海洋權(quán)益': 174, '爭端': 175, '和平解決': 176, '國際爭端': 177, '熱點(diǎn)問題': 178, '負(fù)責(zé)': 179, '大國': 180}簡要介紹一下word2vec模型參數(shù)含義
sentences: 我們要分析的語料,可以是一個列表,或者從文件中遍歷讀出。后面我們會有從文件讀出的例子。
size: 詞向量的維度,默認(rèn)值是100。這個維度的取值一般與我們的語料的大小相關(guān),如果是不大的語料,比如小于100M的文本語料,則使用默認(rèn)值一般就可以了。如果是超大的語料,建議增大維度。
window:即詞向量上下文最大距離,這個參數(shù)在我們的算法原理篇中標(biāo)記為c,window越大,則和某一詞較遠(yuǎn)的詞也會產(chǎn)生上下文關(guān)系。默認(rèn)值為5。在實(shí)際使用中,可以根據(jù)實(shí)際的需求來動態(tài)調(diào)整這個window的大小。如果是小語料則這個值可以設(shè)的更小。對于一般的語料這個值推薦在[5,10]之間。
sg: 即我們的word2vec兩個模型的選擇了。如果是0, 則是CBOW模型,是1則是Skip-Gram模型,默認(rèn)是0即CBOW模型。
hs: 即我們的word2vec兩個解法的選擇了,如果是0, 則是Negative Sampling,是1的話并且負(fù)采樣個數(shù)negative大于0, 則是Hierarchical Softmax。默認(rèn)是0即Negative Sampling。
negative:即使用Negative Sampling時負(fù)采樣的個數(shù),默認(rèn)是5。推薦在[3,10]之間。這個參數(shù)在我們的算法原理篇中標(biāo)記為neg。
cbow_mean: 僅用于CBOW在做投影的時候,為0,則算法中的xw為上下文的詞向量之和,為1則為上下文的詞向量的平均值。在我們的原理篇中,是按照詞向量的平均值來描述的。個人比較喜歡用平均值來表示xw,默認(rèn)值也是1,不推薦修改默認(rèn)值。
min_count:需要計算詞向量的最小詞頻。這個值可以去掉一些很生僻的低頻詞,默認(rèn)是5。如果是小語料,可以調(diào)低這個值。
iter: 隨機(jī)梯度下降法中迭代的最大次數(shù),默認(rèn)是5。對于大語料,可以增大這個值。
alpha: 在隨機(jī)梯度下降法中迭代的初始步長。算法原理篇中標(biāo)記為η,默認(rèn)是0.025。
min_alpha: 由于算法支持在迭代的過程中逐漸減小步長,min_alpha給出了最小的迭代步長值。隨機(jī)梯度下降中每輪的迭代步長可以由iter,alpha, min_alpha一起得出。這部分由于不是word2vec算法的核心內(nèi)容,因此在原理篇我們沒有提到。對于大語料,需要對alpha, min_alpha,iter一起調(diào)參,來選擇合適的三個值。
word2vec的訓(xùn)練:
# 設(shè)置詞語向量維度 num_featrues = 300 # 保證被考慮詞語的最低頻度,對于小語料,設(shè)置為1才可能能輸出所有的詞,因?yàn)橛械脑~可能在每個句子中只出現(xiàn)一次 min_word_count = 1 # 設(shè)置并行化訓(xùn)練使用CPU計算核心數(shù)量 num_workers =4 # 設(shè)置詞語上下文窗口大小 context = 5 #開始訓(xùn)練 model = word2vec.Word2Vec(sentence_word_list, workers=num_workers, size=num_featrues, min_count=min_word_count, window=context) model.init_sims(replace=True)''' # 如果有需要的話,可以輸入一個路徑,保存訓(xùn)練好的模型 model.save("w2vModel1") print(model) #加載模型 model = word2vec.Word2Vec.load("w2vModel1") '''5.利用訓(xùn)練后的word2vec自定義Embedding
word_embeddings = {} count=0 for 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設(shè)為300維元素為0的向量。# 得到句子中全部詞的詞向量后,求平均值,得到句子的向量表示#TypeError: type numpy.ndarray doesn't define __round__ method,將round改為np.roundv = 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)7.開始干正事
#計算句子之間的余弦相似度,構(gòu)成相似度矩陣 sim_mat = np.zeros([len(sentences_list), len(sentences_list)])from sklearn.metrics.pairwise import cosine_similarityfor 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# 利用句子相似度矩陣構(gòu)建圖結(jié)構(gòu),句子為節(jié)點(diǎn),句子相似度為轉(zhuǎn)移概率 nx_graph = nx.from_numpy_array(sim_mat)# 得到所有句子的textrank值 scores = nx.pagerank(nx_graph)# 根據(jù)textrank值對未處理的句子進(jìn)行排序 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')輸出:
第1條摘要:要積極推動高新技術(shù)、先進(jìn)制造、節(jié)能環(huán)保、能源資源、現(xiàn)代農(nóng)業(yè)等領(lǐng)域務(wù)實(shí)合作,反對各種形式的保護(hù)主義,推動貿(mào)易和投資自由化、區(qū)域經(jīng)濟(jì)一體化 第2條摘要:要尊重文明多樣性,尊重各國人民自主選擇的發(fā)展道路,促進(jìn)不同文明和社會制度相互交流借鑒,推動亞太多元文明共同進(jìn)步 第3條摘要:推動和平解決國際爭端和熱點(diǎn)問題,發(fā)揮負(fù)責(zé)任大國作用總結(jié)
以上是生活随笔為你收集整理的TextRank算法讲解与代码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上月用得好好的支付宝获取月账单的Java
- 下一篇: Codeforces Round #66