自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Python中七種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

開發(fā) 后端 算法
我一直在尋找有效關(guān)鍵字提取任務(wù)算法。 目標(biāo)是找到一種算法,能夠以有效的方式提取關(guān)鍵字,并且能夠平衡提取質(zhì)量和執(zhí)行時(shí)間,因?yàn)槲业臄?shù)據(jù)語料庫迅速增加已經(jīng)達(dá)到了數(shù)百萬行。

我一直在尋找有效關(guān)鍵字提取任務(wù)算法。 目標(biāo)是找到一種算法,能夠以有效的方式提取關(guān)鍵字,并且能夠平衡提取質(zhì)量和執(zhí)行時(shí)間,因?yàn)槲业臄?shù)據(jù)語料庫迅速增加已經(jīng)達(dá)到了數(shù)百萬行。 我對于算法一個(gè)主要的要求是提取關(guān)鍵字本身總是要有意義的,即使脫離了上下文的語境也能夠表達(dá)一定的含義。

[[437010]]

本篇文章使用 2000 個(gè)文檔的語料庫對幾種著名的關(guān)鍵字提取算法進(jìn)行測試和試驗(yàn)。

使用的庫列表

我使用了以下python庫進(jìn)行研究

NLTK,以幫助我在預(yù)處理階段和一些輔助函數(shù)

  • RAKE
  • YAKE
  • PKE
  • KeyBERT
  • Spacy

Pandas 和Matplotlib還有其他通用庫

實(shí)驗(yàn)流程

基準(zhǔn)測試的工作方式如下

 

 

我們將首先導(dǎo)入包含我們的文本數(shù)據(jù)的數(shù)據(jù)集。 然后,我們將為每個(gè)算法創(chuàng)建提取邏輯的單獨(dú)函數(shù)

algorithm_name(str: text) → [keyword1, keyword2, ..., keywordn]

然后,我們創(chuàng)建的一個(gè)函數(shù)用于提取整個(gè)語料庫的關(guān)鍵詞。

extract_keywords_from_corpus(algorithm, corpus) → {algorithm, corpus_keywords, elapsed_time}

下一步,使用Spacy幫助我們定義一個(gè)匹配器對象,用來判斷關(guān)鍵字是否對我們的任務(wù)有意義,該對象將返回 true 或 false。

最后,我們會(huì)將所有內(nèi)容打包到一個(gè)輸出最終報(bào)告的函數(shù)中。

數(shù)據(jù)集

我使用的是來自互聯(lián)網(wǎng)的小文本數(shù)數(shù)據(jù)集。這是一個(gè)樣本

 

  1. ['To follow up from my previous questions. . Here is the result!\n'
  2. 'European mead competitions?\nI’d love some feedback on my mead, but entering the Mazer Cup isn’t an option for me, since shipping alcohol to the USA from Europe is illegal. (I know I probably wouldn’t get caught/prosecuted, but any kind of official record of an issue could screw up my upcoming citizenship application and I’m not willing to risk that).\n\nAre there any European mead comps out there? Or at least large beer comps that accept entries in the mead categories and are likely to have experienced mead judges?''Orange Rosemary Booch\n''Well folks, finally happened. Went on vacation and came home to mold.\n''I’m opening a gelato shop in London on Friday so we’ve been up non-stop practicing flavors - here’s one of our most recent attempts!\n'"Does anyone have resources for creating shelf stable hot sauce? Ferment and then water or pressure can?\nI have dozens of fresh peppers I want to use to make hot sauce, but the eventual goal is to customize a recipe and send it to my buddies across the States. I believe canning would be the best way to do this, but I'm not finding a lot of details on it. Any advice?", 'what is the practical difference between a wine filter and a water filter?\nwondering if you could use either', 'What is the best custard base?\nDoes someone have a recipe that tastes similar to Culver’s frozen custard?', 'Mold?\n' 

 

大部分是與食物相關(guān)的。我們將使用2000個(gè)文檔的樣本來測試我們的算法。

我們現(xiàn)在還沒有對文本進(jìn)行預(yù)處理,因?yàn)橛幸恍┧惴ǖ慕Y(jié)果是基于stopwords和標(biāo)點(diǎn)符號(hào)的。

算法

讓我們定義關(guān)鍵字提取函數(shù)。

 

  1. # initiate BERT outside of functions 
  2. bert = KeyBERT() 
  3. # 1. RAKE 
  4. def rake_extractor(text): 
  5. ""
  6. Uses Rake to extract the top 5 keywords from a text 
  7. Arguments: text (str) 
  8. Returns: list of keywords (list) 
  9. ""
  10. r = Rake() 
  11. r.extract_keywords_from_text(text) 
  12. return r.get_ranked_phrases()[:5] 
  13. # 2. YAKE 
  14. def yake_extractor(text): 
  15. ""
  16. Uses YAKE to extract the top 5 keywords from a text 
  17. Arguments: text (str) 
  18. Returns: list of keywords (list) 
  19. ""
  20. keywords = yake.KeywordExtractor(lan="en", n=3, windowsSize=3, top=5).extract_keywords(text) 
  21. results = [] 
  22. for scored_keywords in keywords: 
  23. for keyword in scored_keywords: 
  24. if isinstance(keyword, str): 
  25. results.append(keyword)  
  26. return results  
  27. # 3. PositionRank 
  28. def position_rank_extractor(text): 
  29. ""
  30. Uses PositionRank to extract the top 5 keywords from a text 
  31. Arguments: text (str) 
  32. Returns: list of keywords (list) 
  33. ""
  34. # define the valid Part-of-Speeches to occur in the graph 
  35. pos = {'NOUN''PROPN''ADJ''ADV'
  36. extractor = pke.unsupervised.PositionRank() 
  37. extractor.load_document(text, language='en'
  38. extractor.candidate_selection(pos=pos, maximum_word_number=5) 
  39. # 4. weight the candidates using the sum of their word's scores that are 
  40. # computed using random walk biaised with the position of the words 
  41. in the document. In the graph, nodes are words (nouns and 
  42. # adjectives only) that are connected if they occur in a window of 
  43. # 3 words. 
  44. extractor.candidate_weighting(window=3, pos=pos) 
  45. # 5. get the 5-highest scored candidates as keyphrases 
  46. keyphrases = extractor.get_n_best(n=5) 
  47. results = [] 
  48. for scored_keywords in keyphrases: 
  49. for keyword in scored_keywords: 
  50. if isinstance(keyword, str): 
  51. results.append(keyword)  
  52. return results  
  53. # 4. SingleRank 
  54. def single_rank_extractor(text): 
  55. ""
  56. Uses SingleRank to extract the top 5 keywords from a text 
  57. Arguments: text (str) 
  58. Returns: list of keywords (list) 
  59. ""
  60. pos = {'NOUN''PROPN''ADJ''ADV'
  61. extractor = pke.unsupervised.SingleRank() 
  62. extractor.load_document(text, language='en'
  63. extractor.candidate_selection(pos=pos) 
  64. extractor.candidate_weighting(window=3, pos=pos) 
  65. keyphrases = extractor.get_n_best(n=5) 
  66. results = [] 
  67. for scored_keywords in keyphrases: 
  68. for keyword in scored_keywords: 
  69. if isinstance(keyword, str): 
  70. results.append(keyword)  
  71. return results  
  72. # 5. MultipartiteRank 
  73. def multipartite_rank_extractor(text): 
  74. ""
  75. Uses MultipartiteRank to extract the top 5 keywords from a text 
  76. Arguments: text (str) 
  77. Returns: list of keywords (list) 
  78. ""
  79. extractor = pke.unsupervised.MultipartiteRank() 
  80. extractor.load_document(text, language='en'
  81. pos = {'NOUN''PROPN''ADJ''ADV'
  82. extractor.candidate_selection(pos=pos) 
  83. # 4. build the Multipartite graph and rank candidates using random walk, 
  84. # alpha controls the weight adjustment mechanism, see TopicRank for 
  85. # threshold/method parameters. 
  86. extractor.candidate_weighting(alpha=1.1, threshold=0.74, method='average'
  87. keyphrases = extractor.get_n_best(n=5) 
  88. results = [] 
  89. for scored_keywords in keyphrases: 
  90. for keyword in scored_keywords: 
  91. if isinstance(keyword, str): 
  92. results.append(keyword)  
  93. return results 
  94. # 6. TopicRank 
  95. def topic_rank_extractor(text): 
  96. ""
  97. Uses TopicRank to extract the top 5 keywords from a text 
  98. Arguments: text (str) 
  99. Returns: list of keywords (list) 
  100. ""
  101. extractor = pke.unsupervised.TopicRank() 
  102. extractor.load_document(text, language='en'
  103. pos = {'NOUN''PROPN''ADJ''ADV'
  104. extractor.candidate_selection(pos=pos) 
  105. extractor.candidate_weighting() 
  106. keyphrases = extractor.get_n_best(n=5) 
  107. results = [] 
  108. for scored_keywords in keyphrases: 
  109. for keyword in scored_keywords: 
  110. if isinstance(keyword, str): 
  111. results.append(keyword)  
  112. return results 
  113. # 7. KeyBERT 
  114. def keybert_extractor(text): 
  115. ""
  116. Uses KeyBERT to extract the top 5 keywords from a text 
  117. Arguments: text (str) 
  118. Returns: list of keywords (list) 
  119. ""
  120. keywords = bert.extract_keywords(text, keyphrase_ngram_range=(3, 5), stop_words="english", top_n=5) 
  121. results = [] 
  122. for scored_keywords in keywords: 
  123. for keyword in scored_keywords: 
  124. if isinstance(keyword, str): 
  125. results.append(keyword) 
  126. return results 

 

每個(gè)提取器將文本作為參數(shù)輸入并返回一個(gè)關(guān)鍵字列表。對于使用來講非常簡單。

注意:由于某些原因,我不能在函數(shù)之外初始化所有提取器對象。每當(dāng)我這樣做時(shí),TopicRank和MultiPartiteRank都會(huì)拋出錯(cuò)誤。就性能而言,這并不完美,但基準(zhǔn)測試仍然可以完成。

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

我們已經(jīng)通過傳遞 pos = {'NOUN', 'PROPN', 'ADJ', 'ADV'} 來限制一些可接受的語法模式——這與 Spacy 一起將確保幾乎所有的關(guān)鍵字都是從人類語言視角來選擇的。 我們還希望關(guān)鍵字包含三個(gè)單詞,只是為了有更具體的關(guān)鍵字并避免過于籠統(tǒng)。

從整個(gè)語料庫中提取關(guān)鍵字

現(xiàn)在讓我們定義一個(gè)函數(shù),該函數(shù)將在輸出一些信息的同時(shí)將單個(gè)提取器應(yīng)用于整個(gè)語料庫。

 

  1. def extract_keywords_from_corpus(extractor, corpus): 
  2. """This function uses an extractor to retrieve keywords from a list of documents""" 
  3. extractor_name = extractor.__name__.replace("_extractor"""
  4. logging.info(f"Starting keyword extraction with {extractor_name}"
  5. corpus_kws = {} 
  6. start = time.time() 
  7. # logging.info(f"Timer initiated.") <-- uncomment this if you want to output start of timer 
  8. for idx, text in tqdm(enumerate(corpus), desc="Extracting keywords from corpus..."): 
  9. corpus_kws[idx] = extractor(text) 
  10. end = time.time() 
  11. # logging.info(f"Timer stopped.") <-- uncomment this if you want to output end of timer 
  12. elapsed = time.strftime("%H:%M:%S"time.gmtime(end - start)) 
  13. logging.info(f"Time elapsed: {elapsed}"
  14.  
  15. return {"algorithm": extractor.__name__,  
  16. "corpus_kws": corpus_kws,  
  17. "elapsed_time": elapsed} 

 

這個(gè)函數(shù)所做的就是將傳入的提取器數(shù)據(jù)和一系列有用的信息組合成一個(gè)字典(比如執(zhí)行任務(wù)花費(fèi)了多少時(shí)間)來方便我們后續(xù)生成報(bào)告。

語法匹配函數(shù)

這個(gè)函數(shù)確保提取器返回的關(guān)鍵字始終(幾乎?)意義。 例如,

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

我們可以清楚地了解到,前三個(gè)關(guān)鍵字可以獨(dú)立存在,它們完全是有意義的。我們不需要更多信息來理解關(guān)鍵詞的含義,但是第四個(gè)就毫無任何意義,所以需要盡量避免這種情況。

Spacy 與 Matcher 對象可以幫助我們做到這一點(diǎn)。 我們將定義一個(gè)匹配函數(shù),它接受一個(gè)關(guān)鍵字,如果定義的模式匹配,則返回 True 或 False。

 

  1. def match(keyword): 
  2. """This function checks if a list of keywords match a certain POS pattern""" 
  3. patterns = [ 
  4. [{'POS''PROPN'}, {'POS''VERB'}, {'POS''VERB'}], 
  5. [{'POS''NOUN'}, {'POS''VERB'}, {'POS''NOUN'}], 
  6. [{'POS''VERB'}, {'POS''NOUN'}], 
  7. [{'POS''ADJ'}, {'POS''ADJ'}, {'POS''NOUN'}],  
  8. [{'POS''NOUN'}, {'POS''VERB'}], 
  9. [{'POS''PROPN'}, {'POS''PROPN'}, {'POS''PROPN'}], 
  10. [{'POS''PROPN'}, {'POS''PROPN'}, {'POS''NOUN'}], 
  11. [{'POS''ADJ'}, {'POS''NOUN'}], 
  12. [{'POS''ADJ'}, {'POS''NOUN'}, {'POS''NOUN'}, {'POS''NOUN'}], 
  13. [{'POS''PROPN'}, {'POS''PROPN'}, {'POS''PROPN'}, {'POS''ADV'}, {'POS''PROPN'}], 
  14. [{'POS''PROPN'}, {'POS''PROPN'}, {'POS''PROPN'}, {'POS''VERB'}], 
  15. [{'POS''PROPN'}, {'POS''PROPN'}], 
  16. [{'POS''NOUN'}, {'POS''NOUN'}], 
  17. [{'POS''ADJ'}, {'POS''PROPN'}], 
  18. [{'POS''PROPN'}, {'POS''ADP'}, {'POS''PROPN'}], 
  19. [{'POS''PROPN'}, {'POS''ADJ'}, {'POS''NOUN'}], 
  20. [{'POS''PROPN'}, {'POS''VERB'}, {'POS''NOUN'}], 
  21. [{'POS''NOUN'}, {'POS''ADP'}, {'POS''NOUN'}], 
  22. [{'POS''PROPN'}, {'POS''NOUN'}, {'POS''PROPN'}], 
  23. [{'POS''VERB'}, {'POS''ADV'}], 
  24. [{'POS''PROPN'}, {'POS''NOUN'}], 
  25. matcher = Matcher(nlp.vocab) 
  26. matcher.add("pos-matcher", patterns) 
  27. create spacy object 
  28. doc = nlp(keyword) 
  29. # iterate through the matches 
  30. matches = matcher(doc) 
  31. # if matches is not empty, it means that it has found at least a match 
  32. if len(matches) > 0: 
  33. return True 
  34. return False 

 

基準(zhǔn)測試函數(shù)

我們馬上就要完成了。 這是啟動(dòng)腳本和收集結(jié)果之前的最后一步。

我們將定義一個(gè)基準(zhǔn)測試函數(shù),它接收我們的語料庫和一個(gè)布爾值,用于對我們的數(shù)據(jù)進(jìn)行打亂。 對于每個(gè)提取器,它調(diào)用

extract_keywords_from_corpus 函數(shù)返回一個(gè)包含該提取器結(jié)果的字典。 我們將該值存儲(chǔ)在列表中。

對于列表中的每個(gè)算法,我們計(jì)算

  • 平均提取關(guān)鍵詞數(shù)
  • 匹配關(guān)鍵字的平均數(shù)量
  • 計(jì)算一個(gè)分?jǐn)?shù)表示找到的平均匹配數(shù)除以執(zhí)行操作所花費(fèi)的時(shí)間

我們將所有數(shù)據(jù)存儲(chǔ)在 Pandas DataFrame 中,然后將其導(dǎo)出為 .csv。

 

  1. def get_sec(time_str): 
  2. """Get seconds from time.""" 
  3. h, m, s = time_str.split(':'
  4. return int(h) * 3600 + int(m) * 60 + int(s) 
  5. def benchmark(corpus, shuffle=True): 
  6. """This function runs the benchmark for the keyword extraction algorithms""" 
  7. logging.info("Starting benchmark...\n"
  8.  
  9. # Shuffle the corpus 
  10. if shuffle: 
  11. random.shuffle(corpus) 
  12. # extract keywords from corpus 
  13. results = [] 
  14. extractors = [ 
  15. rake_extractor,  
  16. yake_extractor,  
  17. topic_rank_extractor,  
  18. position_rank_extractor, 
  19. single_rank_extractor, 
  20. multipartite_rank_extractor, 
  21. keybert_extractor, 
  22. for extractor in extractors: 
  23. result = extract_keywords_from_corpus(extractor, corpus) 
  24. results.append(result) 
  25. # compute average number of extracted keywords 
  26. for result in results: 
  27. len_of_kw_list = [] 
  28. for kws in result["corpus_kws"].values(): 
  29. len_of_kw_list.append(len(kws)) 
  30. result["avg_keywords_per_document"] = np.mean(len_of_kw_list) 
  31. # match keywords 
  32. for result in results: 
  33. for idx, kws in result["corpus_kws"].items(): 
  34. match_results = [] 
  35. for kw in kws: 
  36. match_results.append(match(kw)) 
  37. result["corpus_kws"][idx] = match_results 
  38. # compute average number of matched keywords 
  39. for result in results: 
  40. len_of_matching_kws_list = [] 
  41. for idx, kws in result["corpus_kws"].items(): 
  42. len_of_matching_kws_list.append(len([kw for kw in kws if kw])) 
  43. result["avg_matched_keywords_per_document"] = np.mean(len_of_matching_kws_list) 
  44. # compute average percentange of matching keywords, round 2 decimals 
  45. result["avg_percentage_matched_keywords"] = round(result["avg_matched_keywords_per_document"] / result["avg_keywords_per_document"], 2) 
  46.  
  47. create score based on the avg percentage of matched keywords divided by time elapsed (in seconds) 
  48. for result in results: 
  49. elapsed_seconds = get_sec(result["elapsed_time"]) + 0.1 
  50. # weigh the score based on the time elapsed 
  51. result["performance_score"] = round(result["avg_matched_keywords_per_document"] / elapsed_seconds, 2) 
  52.  
  53. delete corpus_kw 
  54. for result in results: 
  55. del result["corpus_kws"
  56. create results dataframe 
  57. df = pd.DataFrame(results) 
  58. df.to_csv("results.csv"index=False
  59. logging.info("Benchmark finished. Results saved to results.csv"
  60. return df 

 

結(jié)果

 

  1. results = benchmark(texts[:2000], shuffle=True

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

下面是產(chǎn)生的報(bào)告

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

我們可視化一下:

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

根據(jù)我們定義的得分公式(

avg_matched_keywords_per_document/time_elapsed_in_seconds), Rake 在 2 秒內(nèi)處理 2000 個(gè)文檔,盡管準(zhǔn)確度不如 KeyBERT,但時(shí)間因素使其獲勝。

如果我們只考慮準(zhǔn)確性,計(jì)算為

avg_matched_keywords_per_document 和 avg_keywords_per_document 之間的比率,我們得到這些結(jié)果

 

Python中7種主要關(guān)鍵詞提取算法的基準(zhǔn)測試

 

從準(zhǔn)確性的角度來看,Rake 的表現(xiàn)也相當(dāng)不錯(cuò)。如果我們不考慮時(shí)間的話,KeyBERT 肯定會(huì)成為最準(zhǔn)確、最有意義關(guān)鍵字提取的算法。Rake 雖然在準(zhǔn)確度上排第二,但是差了一大截。

 

如果需要準(zhǔn)確性,KeyBERT 肯定是首選,如果要求速度的話Rake肯定是首選,因?yàn)樗乃俣葔K,準(zhǔn)確率也算能接受吧。

 

責(zé)任編輯:華軒 來源: 今日頭條
相關(guān)推薦

2023-07-03 12:47:01

2010-08-31 10:57:36

2011-03-24 14:45:48

2011-06-20 14:32:59

關(guān)鍵詞

2020-07-23 10:20:28

物聯(lián)網(wǎng)工業(yè)物聯(lián)網(wǎng)技術(shù)

2011-06-07 18:45:41

關(guān)鍵詞

2018-02-07 16:38:27

算法自然語言文本

2024-06-13 09:05:12

2011-06-14 19:11:38

關(guān)鍵詞

2011-06-21 16:48:21

關(guān)鍵詞SEO

2011-06-24 17:01:44

關(guān)鍵詞

2011-06-22 18:19:40

2011-06-16 17:25:45

關(guān)鍵詞

2013-08-26 15:43:40

AppStore關(guān)鍵詞開發(fā)者應(yīng)用選取關(guān)鍵詞

2020-08-27 07:00:00

游戲游戲測試測試技術(shù)

2011-06-14 10:01:03

長尾關(guān)鍵詞

2011-06-19 12:20:47

長尾關(guān)鍵詞

2015-12-21 09:50:07

2011-05-25 17:58:00

2011-05-25 17:38:56

關(guān)鍵詞
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)