使用NLP從文章中自動提取關鍵字


背景

在研究和新聞文章中,關鍵詞構成了一個重要的組成部分,因為它們提供了文章內容的簡潔表示。關鍵詞在從信息檢索系統,書目數據庫和搜索引擎優化中定位文章方面也起着至關重要的作用。關鍵詞還有助於將文章分類為相關主題或學科。

提取關鍵詞的傳統方法涉及基於文章內容和作者的判斷手動分配關鍵詞。這涉及大量時間和精力,並且在選擇適當的關鍵字方面也可能不准確。隨着自然語言處理(NLP)的出現,關鍵字提取已經發展為有效且高效。

在本文中,我們將結合這兩者 - 我們將在一系列文章上應用NLP來提取關鍵字。

關於數據集

在本文中,我們將從包含大約3,800個摘要的機器學習數據集中提取關鍵字。機器學習原始數據集來自Kaggle - NIPS Paper(https://www.kaggle.com/benhamner/nips-papers/home)。神經信息處理系統(NIPS)是世界頂級機器學習會議之一。該數據集包括迄今為止所有NIPS論文的標題和摘要(從1987年的第一次會議到當前的2016年會議)。

原始數據集還包含文章文本。然而,由於重點是理解關鍵字提取的概念,使用全文可能需要大量的計算,所以只有摘要被用於NLP建模。可以在全文中使用相同的代碼塊來獲得更好的增強關鍵字提取。

高級方法

使用NLP從文章中自動提取關鍵字詳細指南

 

導入數據集

本文使用的數據集是Kaggle上NIPS Paper數據集中提供的papers.csv數據集的子集。僅使用了包含摘要的那些行。標題和摘要已連接在一起,之后文件將另存為制表符分割的* .txt文件。

import pandas
# load the dataset
dataset = pandas.read_csv('papers2.txt', delimiter = ' ')
dataset.head()
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

 

我們可以看到,機器學習數據集包含文章ID,發布年份和摘要。

初步文本探索

在我們繼續進行任何文本預處理之前,建議您根據字數,最常見和最不常見的單詞快速瀏覽數據集。

獲取每個摘要的字數

#Fetch wordcount for each abstract
dataset['word_count'] = dataset['abstract1'].apply(lambda x: len(str(x).split(" ")))
dataset[['abstract1','word_count']].head()
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

 

##Descriptive statistics of word counts
dataset.word_count.describe()
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

 

每個摘要的平均字數約為156個字。單詞計數范圍從最小值27到最大值325.單詞計數對於向我們指示我們正在處理的數據集的大小以及跨行的單詞計數的變化非常重要。

最常見和最不常見的詞

瀏覽一下最常用的單詞,不僅可以洞察經常使用的單詞,還可以洞察可能是特定於數據的潛在停止詞的單詞。比較最常用的單詞和默認的英語停止詞,我們將得到需要添加到自定義停止詞列表中的單詞列表。

#Identify common words
freq = pandas.Series(' '.join(dataset['abstract1']).split()).value_counts()[:20]
freq
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

最常見的詞

#Identify uncommon words
freq1 = pandas.Series(' '.join(dataset
['abstract1']).split()).value_counts()[-20:]
freq1
使用NLP從文章中自動提取關鍵字詳細指南

 

文字預處理

使用NLP從文章中自動提取關鍵字詳細指南

 

文本預處理的目標

稀疏性:在文本挖掘中,基於詞頻創建巨大的矩陣,其中許多單元具有零值。這個問題被稱為稀疏性,並使用各種技術最小化。

文本預處理可分為兩大類 - 噪聲消除和歸一化。對核心文本分析而言冗余的數據組件可視為噪聲。

使用NLP從文章中自動提取關鍵字詳細指南

文本預處理

處理同一個單詞的多個出現/表示稱為標准化。歸一化有兩種類型 - 詞干提取和詞形還原。讓我們考慮一下learn這個詞的各種版本的例子 - learn, learned, learning, learner。歸一化會將所有這些單詞轉換為單個標准化版本 - “learn”。

詞干通過刪除后綴來歸一化文本。

Lemmatisation是一種更先進的技術,它基於基於詞根。

以下示例說明了詞干和lemmatisation的工作方式:

from nltk.stem.porter import PorterStemmer
from nltk.stem.wordnet import WordNetLemmatizer
lem = WordNetLemmatizer()
stem = PorterStemmer()
word = "inversely"
print("stemming:",stem.stem(word))
print("lemmatization:", lem.lemmatize(word, "v"))
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

 

要對我們的數據集執行文本預處理,我們將首先導入所需的Python庫。

# Libraries for text preprocessing
import re
import nltk
#nltk.download('stopwords')
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
from nltk.tokenize import RegexpTokenizer
#nltk.download('wordnet')
from nltk.stem.wordnet import WordNetLemmatizer
使用NLP從文章中自動提取關鍵字詳細指南

 

刪除停止詞(stopwords):停止詞包括句子中的大量介詞,代詞,連詞等。在分析文本之前,需要刪除這些單詞,以便經常使用的單詞主要是與上下文相關的單詞,而不是文本中使用的常用單詞。

python nltk庫中有一個默認的停止詞列表。此外,我們可能希望添加特定於上下文的停止詞,我們在開頭列出的“最常用詞”對此有用。我們現在將看到如何創建一個停止詞列表以及如何添加自定義停止詞:

##Creating a list of stop words and adding custom stopwords
stop_words = set(stopwords.words("english"))
##Creating a list of custom stopwords
new_words = ["using", "show", "result", "large", "also", "iv", "one", "two", "new", "previously", "shown"]
stop_words = stop_words.union(new_words)
使用NLP從文章中自動提取關鍵字詳細指南

 

我們現在將逐步執行預處理任務,以獲得清理和歸一化的文本語料庫:

corpus = []
for i in range(0, 3847):
#Remove punctuations
text = re.sub('[^a-zA-Z]', ' ', dataset['abstract1'][i])

#Convert to lowercase
text = text.lower()

#remove tags
text=re.sub("</?.*?>"," <> ",text)

# remove special characters and digits
text=re.sub("(\d|\W)+"," ",text)

##Convert to list from string
text = text.split()

##Stemming
ps=PorterStemmer()
#Lemmatisation
lem = WordNetLemmatizer()
text = [lem.lemmatize(word) for word in text if not word in
stop_words]
text = " ".join(text)
corpus.append(text)
使用NLP從文章中自動提取關鍵字詳細指南

 

現在讓我們從語料庫中查看一個項:

#View corpus item
corpus[222]
使用NLP從文章中自動提取關鍵字詳細指南

 

數據探索

現在,我們將可視化我們在預處理后創建的文本語料庫,以獲得對最常用單詞的分析。

#Word cloud
from os import path
from PIL import Image
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
import matplotlib.pyplot as plt
% matplotlib inline
wordcloud = WordCloud(
background_color='white',
stopwords=stop_words,
max_words=100,
max_font_size=50,
random_state=42
).generate(str(corpus))
print(wordcloud)
fig = plt.figure(1)
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
fig.savefig("word1.png", dpi=900)
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

詞雲

文本准備

語料庫中的文本需要轉換為可由機器學習算法解釋的格式。這種轉換有兩部分 - 標記化和矢量化。

標記化是將連續文本轉換為單詞列表的過程。然后通過矢量化過程將單詞列表轉換為整數矩陣。矢量化也稱為特征提取。

對於文本准備,我們使用bag of words模型,它忽略了單詞的順序,只考慮單詞頻率。

創建單詞計數向量

作為轉換的第一步,我們將使用CountVectoriser來標記文本並構建已知單詞的詞匯表。我們首先創建CountVectoriser類的變量“cv”,然后調用fit_transform函數來學習和構建詞匯表。

from sklearn.feature_extraction.text import CountVectorizer
import re
cv=CountVectorizer(max_df=0.8,stop_words=stop_words, max_features=10000, ngram_range=(1,3))
X=cv.fit_transform(corpus)
使用NLP從文章中自動提取關鍵字詳細指南

 

現在讓我們了解傳遞給函數的參數:

  • cv = CountVectorizer(max_df = 0.8,stop_words = stop_words,max_features = 10000,ngram_range =(1,3))
  • max_df - 構建詞匯表時,忽略文檔頻率嚴格高於給定閾值的項(語料庫特定的停止詞)。這是為了確保我們只有與上下文相關的單詞而不是常用單詞。
  • max_features - 確定矩陣中的列數。
  • n-gram范圍 - 我們希望查看單個單詞,兩個單詞(bi-gram)和三個單詞(tri-gram)組合的列表。

返回具有整個詞匯長度的編碼向量。

list(cv.vocabulary_.keys())[:10]
使用NLP從文章中自動提取關鍵字詳細指南

 

可視化前N個uni-grams, bi-grams & tri-grams

我們可以使用CountVectoriser來顯示前20個unigrams,bi-gram和tri-gram。

#Most frequently occuring words
def get_top_n_words(corpus, n=None):
vec = CountVectorizer().fit(corpus)
bag_of_words = vec.transform(corpus)
sum_words = bag_of_words.sum(axis=0)
words_freq = [(word, sum_words[0, idx]) for word, idx in
vec.vocabulary_.items()]
words_freq =sorted(words_freq, key = lambda x: x[1],
reverse=True)
return words_freq[:n]
#Convert most freq words to dataframe for plotting bar plot
top_words = get_top_n_words(corpus, n=20)
top_df = pandas.DataFrame(top_words)
top_df.columns=["Word", "Freq"]
#Barplot of most freq words
import seaborn as sns
sns.set(rc={'figure.figsize':(13,8)})
g = sns.barplot(x="Word", y="Freq", data=top_df)
g.set_xticklabels(g.get_xticklabels(), rotation=30)
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

最頻繁出現的uni-grams的條形圖

#Most frequently occuring Bi-grams
def get_top_n2_words(corpus, n=None):
vec1 = CountVectorizer(ngram_range=(2,2),
max_features=2000).fit(corpus)
bag_of_words = vec1.transform(corpus)
sum_words = bag_of_words.sum(axis=0)
words_freq = [(word, sum_words[0, idx]) for word, idx in
vec1.vocabulary_.items()]
words_freq =sorted(words_freq, key = lambda x: x[1],
reverse=True)
return words_freq[:n]
top2_words = get_top_n2_words(corpus, n=20)
top2_df = pandas.DataFrame(top2_words)
top2_df.columns=["Bi-gram", "Freq"]
print(top2_df)
#Barplot of most freq Bi-grams
import seaborn as sns
sns.set(rc={'figure.figsize':(13,8)})
h=sns.barplot(x="Bi-gram", y="Freq", data=top2_df)
h.set_xticklabels(h.get_xticklabels(), rotation=45)
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

最頻繁出現的bi-grams的條形圖

#Most frequently occuring Tri-grams
def get_top_n3_words(corpus, n=None):
vec1 = CountVectorizer(ngram_range=(3,3),
max_features=2000).fit(corpus)
bag_of_words = vec1.transform(corpus)
sum_words = bag_of_words.sum(axis=0)
words_freq = [(word, sum_words[0, idx]) for word, idx in
vec1.vocabulary_.items()]
words_freq =sorted(words_freq, key = lambda x: x[1],
reverse=True)
return words_freq[:n]
top3_words = get_top_n3_words(corpus, n=20)
top3_df = pandas.DataFrame(top3_words)
top3_df.columns=["Tri-gram", "Freq"]
print(top3_df)
#Barplot of most freq Tri-grams
import seaborn as sns
sns.set(rc={'figure.figsize':(13,8)})
j=sns.barplot(x="Tri-gram", y="Freq", data=top3_df)
j.set_xticklabels(j.get_xticklabels(), rotation=45)
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

最頻繁發生的tri-grams的條形圖

轉換為整數矩陣

細化單詞計數的下一步是使用TF-IDF向量化器。從countVectoriser獲得的單詞計數的不足之處在於,大量的某些常用單詞可能會稀釋語料庫中更多上下文特定單詞的影響。這被TF-IDF矢量化器克服,該矢量化器懲罰在整個文檔中出現若干次的單詞。TF-IDF是詞頻分數,它突出顯示對上下文更重要的單詞,而不是那些在文檔中頻繁出現的單詞。

TF-IDF由2個組成部分組成:

  • TF - TF意思是詞頻(Term Frequency)
  • IDF - IDF意思是逆文本頻率指數(Inverse Document Frequency)
使用NLP從文章中自動提取關鍵字詳細指南

 

from sklearn.feature_extraction.text import TfidfTransformer

tfidf_transformer=TfidfTransformer(smooth_idf=True,use_idf=True)
tfidf_transformer.fit(X)
# get feature names
feature_names=cv.get_feature_names()

# fetch document for which keywords needs to be extracted
doc=corpus[532]

#generate tf-idf for the given document
tf_idf_vector=tfidf_transformer.transform(cv.transform([doc]))
使用NLP從文章中自動提取關鍵字詳細指南

 

根據TF-IDF分數,我們可以提取分數最高的單詞來獲取文檔的關鍵字

#Function for sorting tf_idf in descending order
from scipy.sparse import coo_matrix
def sort_coo(coo_matrix):
tuples = zip(coo_matrix.col, coo_matrix.data)
return sorted(tuples, key=lambda x: (x[1], x[0]), reverse=True)

def extract_topn_from_vector(feature_names, sorted_items, topn=10):
"""get the feature names and tf-idf score of top n items"""

#use only topn items from vector
sorted_items = sorted_items[:topn]

score_vals = []
feature_vals = []

# word index and corresponding tf-idf score
for idx, score in sorted_items:

#keep track of feature name and its corresponding score
score_vals.append(round(score, 3))
feature_vals.append(feature_names[idx])

#create a tuples of feature,score
#results = zip(feature_vals,score_vals)
results= {}
for idx in range(len(feature_vals)):
results[feature_vals[idx]]=score_vals[idx]

return results
#sort the tf-idf vectors by descending order of scores
sorted_items=sort_coo(tf_idf_vector.tocoo())
#extract only the top n; n here is 10
keywords=extract_topn_from_vector(feature_names,sorted_items,5)

# now print the results
print(" Abstract:")
print(doc)
print(" Keywords:")
for k in keywords:
print(k,keywords[k])
使用NLP從文章中自動提取關鍵字詳細指南

 

使用NLP從文章中自動提取關鍵字詳細指南

 

最后

理想情況下,對於IDF計算有效,它應該基於大型語料庫和需要提取關鍵字的文本的良好代表。在我們的示例中,如果我們使用完整的文章文本而不是摘要,IDF提取將更加有效。但是,考慮到數據集的大小,我將語料庫限制為僅用於演示目的的摘要。

這是一種相當簡單的方法來理解NLP的基本概念,並在現實生活中使用一些python代碼提供良好的實踐練習。可以使用相同的方法從新聞源和社交媒體源中提取關鍵字。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM