RAKE:快速自动抽取关键词算法
今天在github上看到一个用来计算英文文本中关键词得分的,就是输入一坨英文文本,计算出里面关键词(包括单词和词组)的得分,由高到低排序。
按照文档说明,使用的RAKE算法(Rapid Automtic Keyword Exraction algorithm),我觉得该代码有很多咱们常用的分词、词频统计等方面的功能,写的很python范儿。
我认为我们可以学习里面很多技巧,闲来无事,对词频统计、关键词提取都可以多看看本代码。下面开始阅读源码,请找半个小时时间,安静的阅读。文末会附有脚本。
stopword资源
SMART (Salton,1971).
Available at ftp://ftp.cs.cornell.edu/pub/smart/english.stop
判断是否为数字
def isnum(s):
"""
:param s: 输入的数据为字符格式
:return: 返回bool值。s为数字,则返回值为True
"""
try:
float(s) if '.' in s else int(s)
return True
except ValueError:
return False
导入停止词库
从停止词的txt文件中读入停止词
def loadStopWords(stopWordFile):
"""
:param stopWordFile: 停止词txt文件
:return: 返回停止词列表
"""
stopWords = []
for line in open(stopWordFile).readlines():
stopWords.append(line.strip())
return stopWords
分词函数
将句子分为一个个的词语
def separatewords(text, minWordReturnSize):
"""
:param text: 输入的英文文本
:param minWordReturnSize:保留字符长度大于minWordReturnSize的单词
:return:返回分词列表
"""
# \w 匹配开头是单词字符的字符
splitter = re.compile('[^\w]')
words = []
for singleWord in splitter.split(text):
currWord = singleWord.strip().lower()
#保留最小长度大于minWordReturnSize,字符非空,不是数字的字符作为词语
if len(currWord) > minWordReturnSize and currWord != '' and not isnum(currWord):
words.append(currWord)
return words
分句函数
将文本分为一个个的句子
def splitSentences(text):
"""
:param text: 输入的文本数据
:return: 返回句子列表
"""
#这个正则我是找打的,不是自己写的,拿来直接用吧。
#大体意思是遇到这几个句号逗号冒号分好号,直接将其作为分隔符
sentenceDelimiters = re.compile(u'[.!?,;:\t\\-\\"\\(\\)\\\'\u2019\u2013]')
sentenceList = [x for x in sentenceDelimiters.split(text) if x!='']
return sentenceList
停用词正则表达式列表
构建停用词正则表达式列表,后面的函数调用此列表,当遇到停用词正则匹配到的字符,可以剔除掉文本中该停用词。
我们先看一个简单的例子,假设a是停用词,我们要将文本中的停用词标注出来,方便操作,可以用'\ba\b'匹配a。
\b 匹配单词,上面用的\b是因为\是转义字符,所以要用两\
text = 'a good man,handsome a man'
print(re.compile('\ba\b').findall(text))
匹配到text中的a
['a','a']
上面针对的一个停用词,如果是很多的停用词,如何匹配出文本中的停用词呢?
下面我们看看该函数
def buildStopwordRegExPattern(pathtostopwordsfile):
"""
:param pathtostopwordsfile: 停止词txt文件
:return: 返回停用词匹配的正则表达式列表
"""
#调用前面的停止词读入函数,返回列表
stopwordlist = loadStopWords(pathtostopwordsfile)
stopwordregexlist = []
for wrd in stopwordlist:
#正则 '\\b'就是 \b,用来匹配停用词
wrdregex = '\\b' + wrd + '\\b' #
stopwordregexlist.append(wrdregex)
#将多个停用词匹配模式用“或”(|)的方式连起来,
#遇到这所有的停用词,都会被匹配出来
#re.IGNORECASE 使匹配对大小写不敏感
stopwordpattern = re.compile('|'.join(stopwordregexlist), re.IGNORECASE)
return stopwordpattern
生成词组(候选词)
文本分成句子列表后,使用停用词匹配模式剔除掉停用词后的文本数据,我们可以暂时生成词组(候选的单词)作为初步的分词结果。
def generateCandidateKeywords(sentenceList, stopwordpattern):
"""
:param sentenceList: 句子列表
:param stopwordpattern: 停用词正则表达式列表
:return:
"""
phraseList = []
for s in sentenceList:
tmp = re.sub(stopwordpattern, '|', s.strip())
phrases = tmp.split("|")
for phrase in phrases:
phrase = phrase.strip().lower()
if (phrase != ""):
phraseList.append(phrase)
return phraseList
测试
text = "Compatibility of Im systems 20 of linear constraints over the set of natural numbers. Criteria of compatibility of a system of linear Diophantine equations, strict inequations, and nonstrict inequations are considered. Upper bounds for components of a minimal set of solutions and algorithms of construction of minimal generating sets of solutions for all types of systems are given. These criteria and the corresponding algorithms for constructing a minimal supporting set of solutions can be used in solving all the considered types of systems and systems of mixed types."
sentenceList = splitSentences(text)
stopwordpattern = buildStopwordRegExPattern(pathtostopwordsfile='SmartStoplist.txt')
print(generateCandidateKeywords(sentenceList, stopwordpattern))
测试结果
['compatibility', 'im systems 20', 'linear constraints', 'set', 'natural numbers', 'criteria', 'compatibility', 'system', 'linear diophantine equations', 'strict inequations', 'nonstrict inequations', 'considered', 'upper bounds', 'components', 'minimal set', 'solutions', 'algorithms', 'construction', 'minimal generating sets', 'solutions', 'types', 'systems', 'criteria', 'algorithms', 'constructing', 'minimal supporting set', 'solutions', 'solving', 'considered types', 'systems', 'systems', 'mixed types']
单词得分
根据单词的字符长度和词频计算该单词的得分
def calculateWordScores(phraseList):
"""
:param phraseList:输入候选词组列表
:return: 返回单词得分
"""
wordfreq = {}
worddegree = {}
for phrase in phraseList:
#对候选词组进行分词
wordlist = separatewords(phrase, 0)
wordlistlength = len(wordlist)
wordlistdegree = wordlistlength - 1
#如果wordlistdegree > 3: wordlistdegree = 3 #exp.
for word in wordlist:
#对wordfreq字典初始化设置word词频为0
wordfreq.setdefault(word, 0)
wordfreq[word] += 1
worddegree.setdefault(word, 0)
worddegree[word] += wordlistdegree
#计算词语得分Wordscores = worddegree(word)/wordfre(word)
wordscore = {}
for item in wordfreq:
wordscore.setdefault(item, 0)
wordscore[item] = worddegree[item] / (wordfreq[item] * 1.0)
return wordscore
词组得分
def generateCandidateKeywordScores(phraseList, wordscore):
"""
计算词组列表各自的得分
:param phraseList: 词组列表
:param wordscore: 单词得分
:return: 词组得分字典
"""
keywordcandidates = {}
for phrase in phraseList:
keywordcandidates.setdefault(phrase, 0)
wordlist = separatewords(phrase, 0)
candidatescore = 0
for word in wordlist:
candidatescore += wordscore[word]
keywordcandidates[phrase] = candidatescore
return keywordcandidates
抽取关键词
调用前面所有的函数,对文本抽取关键词。返回的是列表,含有每个关键词的得分,由高到低排序。
def rake(text):
"""
对text进行关键词抽取
:param text: 待分析的文本数据
:return: 返回关键词列表,是有顺序带词组得分的元组
返回的数据形如:
[('minimal generating sets', 5.666666666666667),('linear diophantine equations', 5.5),...]
"""
sentenceList = splitSentences(text)
stoppath = os.path.join(os.path.dirname(__file__), "SmartStoplist.txt")
stopwordpattern = buildStopwordRegExPattern(stoppath)
#将句子列表生成词组列表
phraseList = generateCandidateKeywords(sentenceList, stopwordpattern)
# 计算每个词的得分
wordscores = calculateWordScores(phraseList)
#计算词组的得分
keywordcandidates = generateCandidateKeywordScores(phraseList, wordscores)
sortedKeywords = sorted(keywordcandidates.items(), key=lambda x:x[1], reverse=True)
return sortedKeywords
历史文章:
数据采集
【视频】有了selenium,小白也可以自豪的说:“去TMD的抓包、cookie”
【视频】快来get新技能--抓包+cookie,爬微博不再是梦
文本处理分析
图片数据处理
其他
代码下载
链接: https://pan.baidu.com/s/1kVIIJBL 密码: vj49