TextRank算法讲解与代码实现
參考文章:https://www.cnblogs.com/Luv-GEM/p/10884493.html
PageRank
在TextRank之前我們需要先了解一下PageRank算法。事實上它啟發了TextRank!PageRank主要用于對在線搜索結果中的網頁進行排序。
PageRank對于每個網頁頁面都給出一個正實數,表示網頁的重要程度,PageRank值越高,表示網頁越重要,在互聯網搜索的排序中越可能被排在前面。
假設整個互聯網是一個有向圖,節點是網頁,每條邊是轉移概率。網頁瀏覽者在每個頁面上依照連接出去的超鏈接,以等概率跳轉到下一個網頁,并且在網頁上持續不斷地進行這樣的隨機跳轉,這個過程形成了一階馬爾科夫鏈,比如下圖:
每個笑臉是一個網頁,既有其他網頁跳轉到該網頁,該網頁也會跳轉到其他網頁。在不斷地跳轉之后,這個馬爾科夫鏈會形成一個平穩分布,而PageRank就是這個平穩分布,每個網頁的PageRank值就是平穩概率。
PageRank的核心公式是PageRank值的計算公式。這個公式來自于《統計學習方法》,等號右邊的平滑項(通過某種處理,避免一些突變的畸形值,盡可能接近實際情況)不是(1-d),而是(1-d)/n。
阻尼系數d的意義是,在任意時刻,用戶到達某頁面后并繼續向后瀏覽的概率。1-d就是用戶停止點擊,隨機跳到新URL的概率。
加平滑項是因為有些網頁沒有跳出去的鏈接,那么轉移到其他網頁的概率將會是0,這樣就無法保證存在馬爾科夫鏈的平穩分布。
于是,我們假設網頁以等概率(1/n)跳轉到任何網頁,再按照阻尼系數d,對這個等概率(1/n)與存在鏈接的網頁的轉移概率進行線性組合,那么馬爾科夫鏈一定存在平穩分布,一定可以得到網頁的PageRank值。
所以PageRank的定義意味著網頁瀏覽者按照以下方式在網上隨機游走:以概率d按照存在的超鏈接隨機跳轉,以等概率從超鏈接跳轉到下一個頁面;或以概率(1-d)進行完全隨機跳轉,這時以等概率(1/n)跳轉到任意網頁。
PageRank的計算是一個迭代過程,先假設一個初始的PageRank分布,通過迭代,不斷計算所有網頁的PageRank值,直到收斂為止,也就是:
這篇文章里有詳細的例子:https://www.cnblogs.com/cuiyubo/p/10175268.html
TextRank
兩種算法的相似之處:
- 用句子代替網頁
- 任意兩個句子的相似性等價于網頁轉換概率
- 相似性得分存儲在一個方形矩陣中,類似于PageRank的矩陣M
不過公式有些小的差別,那就是用句子的相似度類比于網頁轉移概率,用歸一化的句子相似度代替了PageRank中相等的轉移概率,這意味著在TextRank中,所有節點的轉移概率不會完全相等。
TextRank算法是一種抽取式的無監督的文本摘要方法。讓我們看一下我們將遵循的TextRank算法的流程:
代碼實現
1.爬取中國黨員網上一篇文章并保存
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項,代表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)2.打開文件:
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))輸出:
前10個句子為:['亞太地區影響最大的議會間組織——亞太議會論壇28日召在符拉迪沃斯托克召開年會', '中國全國人大常委會委員長吳邦國在與會發言中重申,堅持和平發展道路是中國基于時代發展潮流和自身根本利益作出的戰略抉擇,不會因為綜合國力和國際地位的變化而改變', '亞太議會論壇成立于1993年,擁有中國、俄羅斯、美國等27個成員國', '年會是這個論壇的最高決策機構,每年輪流在太平洋兩岸舉行', '據了解,本屆年會為期3天,與會代表將圍繞地區安全、經濟貿易、區域合作等議題進行坦誠對話', '吳邦國在年會主旨發言中闡述了中方在事關亞太地區和平發展重大問題上的原則主張', '他指出,促進亞太地區和平合作發展,是亞太各國的共同責任,各方要從戰略高度審視地區形勢和彼此關系,努力擴大共識、付諸行動', '“我們要摒棄冷戰思維和零和博弈觀念,相互尊重彼此主權和核心利益,推動建立公平有效的地區安全機制', '要積極推動高新技術、先進制造、節能環保、能源資源、現代農業等領域務實合作,反對各種形式的保護主義,推動貿易和投資自由化、區域經濟一體化', '要尊重文明多樣性,尊重各國人民自主選擇的發展道路,促進不同文明和社會制度相互交流借鑒,推動亞太多元文明共同進步'] 句子總數: 193.分詞,這里的停用詞用的網上的,很容易搜到
#加載停用詞 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_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個句子分詞后的結果為:\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.cache Loading model cost 0.990 seconds. Prefix dict has been built succesfully. 一共有 19 個句子。前10個句子分詞后的結果為:[['亞太地區', '影響', '議會', '間', '組織', '亞太', '議會', '論壇', '日召', '符拉迪沃斯托克', '年會'], ['中國', '全國人大常委會', '委員長', '吳邦國', '與會', '發言', '中', '重申', '和平', '發展', '道路', '中國', '時代', '發展', '潮流', '根本利益', '作出', '戰略', '抉擇', '綜合國力', '國際', '地位', '變化', '改變'], ['亞太', '議會', '論壇', '成立', '擁有', '中國', '俄羅斯', '美國', '成員國'], ['年會', '論壇', '決策機構', '輪流', '太平洋', '兩岸'], ['本屆', '年會', '為期', '天', '與會代表', '圍繞', '地區', '經濟', '貿易', '區域合作', '議題', '坦誠', '對話'], ['吳邦國', '主旨', '發言', '中', '闡述', '中方', '事關', '亞太地區', '和平', '發展', '原則'], ['指出', '亞太地區', '和平', '合作', '發展', '亞太', '各國', '責任', '各方', '戰略', '高度', '審視', '地區', '形勢', '關系', '努力', '共識', '付諸行動'], ['摒棄', '冷戰', '思維', '博弈', '觀念', '相互尊重', '主權', '核心', '利益', '推動', '建立', '公平', '地區', '機制'], ['推動', '高新技術', '先進', '制造', '節能', '環保', '能源', '資源', '現代農業', '領域', '務實', '合作', '反對', '形式', '保護主義', '推動', '貿易', '投資', '自由化', '區域', '經濟', '一體化'], ['尊重', '文明', '多樣性', '尊重', '各國', '自主', '選擇', '發展', '道路', '文明', '社會制度', '相互', '交流', '借鑒', '推動', '亞太', '多元', '文明', '共同進步']]數據預處理后句子的數量不變!4.利用word2vec生成詞向量
Word2Vec之類的模型,準確來說應該是“自監督”的,它事實上訓練了一個語言模型,通過語言模型來獲取詞向量。
所謂語言模型,就是通過前個字預測下一個字的概率,就是一個多分類器而已,我們輸入one hot,然后連接一個全連接層,然后再連接若干個層,最后接一個softmax分類器,就可以得到語言模型了,然后將大批量文本輸入訓練就行了,最后得到第一個全連接層的參數,就是字、詞向量表,當然,Word2Vec還做了大量的簡化,但是那都是在語言模型本身做的簡化,它的第一層還是全連接層,全連接層的參數就是字、詞向量表。
輸出:
{'發展': 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=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設為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.開始干正事
#計算句子之間的余弦相似度,構成相似度矩陣 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# 利用句子相似度矩陣構建圖結構,句子為節點,句子相似度為轉移概率 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')輸出:
第1條摘要:要積極推動高新技術、先進制造、節能環保、能源資源、現代農業等領域務實合作,反對各種形式的保護主義,推動貿易和投資自由化、區域經濟一體化 第2條摘要:要尊重文明多樣性,尊重各國人民自主選擇的發展道路,促進不同文明和社會制度相互交流借鑒,推動亞太多元文明共同進步 第3條摘要:推動和平解決國際爭端和熱點問題,發揮負責任大國作用總結
以上是生活随笔為你收集整理的TextRank算法讲解与代码实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上月用得好好的支付宝获取月账单的Java
- 下一篇: Codeforces Round #66