@ArrowLLL
2017-04-20T13:49:20.000000Z
字数 4096
阅读 4851
python 机器学习 爬虫
主页地址 : 月光森林
信息内容安全课杨老师讲了一个tf-idf算法,用于提取一篇文档的关键词。觉得蛮好玩又正好练习python,所以就试着写了一下,特此记录,各位看官请轻拍板砖。
偷个懒,直接贴维基百科的解释:
至于原理,同样贴图(没错,我就这么懒了怎么样吧。。→_→) :
如果看维基还是了解不清楚的话,推荐阮一峰大神的博客,这个也是我们的老师上课讲的东西。
至于其中的数学原理,从维基的原理就很容易看出来,基础还是“贝叶斯定理”,另外一点就是idf的值这里使用到了熵的概念。推荐这篇博客的介绍 : TF-IDF模型的概率解释
(少壮不努力, 老大学数学。。。囧rz)
操作系统 : ubuntu 16.04
python版本 :python3.5.2
引入的python组件 :
sudo pip3 install jieba3k 直接安装sudo pip3 install numpy 安装sudo pip3 install scipy 安装sudo pip3 install scikit-learn 安装语料库准备, 努努书坊-鲁迅-伪自由书 。当然是用爬虫爬喽~
如果对爬虫理解有问题可参考本人之前的博客 —— 第一个爬虫:爬去古诗中带‘月’的诗句 。爬取的方法并没有很大的改进 (太弱只能写基础的。。。orz)
三步走 :
附上代码
#!usr/bin/python3#coding=utf-8import reimport osfrom urllib.request import urlopenfrom urllib.error import HTTPErrorfrom bs4 import BeautifulSoupdef geturl(url):try :html = urlopen(url)except HTTPError as e :return Nonetry :bsObj = BeautifulSoup(html, 'lxml')except AttributeError as e :return Nonereturn bsObjdef getArticle(url, f) :articlePage = geturl(url)article = articlePage.findAll('p')for paragraph in article :print (paragraph.get_text(), file = f)start = "http://www.kanunu8.com/book/4433/"page = geturl(start)tr = page.findAll('tr', {'bgcolor' : '#ffffff'})links = (re.findall(r'<td><a href="(.*?)">(.*?)</a></td>', str(tr)))if not os.path.isdir('article') :os.mkdir('article')for link in links :with open('./article/' + link[1] + '.txt', 'wt+') as f :f.write(link[1])getArticle(start + link[0], f)print ('---< ' , link[1], ' > get ---')
这个爬虫只是在之前的基础上加了一点新功能,将爬取结果都放在了一个文件夹下,使用到了 os 模块的 os.path.isdir(str) 函数和 os.mkdir(str) 函数。 前者用于检查 str 这个文件夹是否存在,后者用于创建一个名为 str 的文件夹 。
爬取的结果如下:
然后是爬取结果的一部分 :
仍然是三步走 :
CountVectorizer()类 和 TfidfTransformer()类 完成对词语的词频分析并获得每篇文章对应的词语的idf值, 可参考[python] 使用scikit-learn工具计算文本TF-IDF值这篇文章的第三部分;先附上代码,然后作说明 :
#coding: utf-8import osimport jiebaimport jieba.posseg as psegfrom sklearn.feature_extraction.text import CountVectorizerfrom sklearn.feature_extraction.text import TfidfTransformerimport numpt as nppath = './article/'titlelist, wordslist = [], []for fileName in os.listdir(path) :titlelist.append(''.join(fileName[:-4].split()))with open(path + fileName) as f :text = f.read()text = ''.join(text.split())seg_list = jieba.cut(text)wordslist.append(' '.join(seg_list))vec = CountVectorizer()wordFrequence = vec.fit_transform(wordslist)words = vec.get_feature_names()trans = TfidfTransformer()tfidf = trans.fit_transform(wordFrequence)wordsWeight = tfidf.toarray()n = int(input('输入关键字的个数 : '))while(n > 5 or n < 0) :n = int(input('输入数字应大于零并且小于等于5 : '))for (title, weight) in zip(titlelist, wordsWeight) :print (title, ' : ')loc = np.argsort(-weight)for i in range(n) :print('\t#' + str(i + 1) + ':', words[loc[i]])print()input('any key to continue...')
对于初学者(比如我)其中可能会不太懂点:
os.listpath(path) 函数 返回一个list, 存的是path 文件夹的子目录中文件或文件夹的名字 ;''.join(text.split()) 将所有文章中的回车、空格删除 ;对于这一段 :
vec = CountVectorizer()wordFrequence = vec.fit_transform(wordslist)words = vec.get_feature_names()trans = TfidfTransformer()tfidf = trans.fit_transform(wordFrequence)wordsWeight = tfidf.toarray()
看过给出链接的第三部分也就能很好地理解了,不再解释;
zip() 用于要同时遍历两个或多个 list ,将 list 打包,使用迭代器迭代获取 list 中的值。for i in range(n) 中,每次取出当前处理文档的最大tf-idf值的索引 loc , 然后在获得的词语列表words 中取出对应的词语,取出一个删除一个,即 del 的作用,然后继续取词知道取满 n 个为止。
以上です~
在结巴分词的文档里看到一个提取关键词的函数:
jieba.analyse.extract_tags(sentence,topK)
函数有3点要求:
- 需要先import jieba.analyse
- setence为待提取的文本
- topK为返回几个TF/IDF权重最大的关键词,默认值为20
由此可以直接对中文文档做关键字提取,附上代码:
#!usr/bin/python3# -*- coding: utf-8 -*-import osimport jieba.analyse as jiebanysimport osimport jieba.analyse as jiebaysdef getTag(fileLocation, k) :with open(fileLocation) as f :txt = f.read()# 重点 ----- 在 ----- 这里tags = jiebays.extract_tags(txt, topK = k)return (" ".join(tags)).split()if __name__ == '__main__' :n = int(input('输入关键字的个数 : '))while(n > 5 or n < 0) :n = int(input('输入数字应大于零并且小于等于5 : '))path = './article/'for fileName in os.listdir(path) :tagList = getTag(path + fileName, n)print (fileName + ' : ')for i in range(n) :print ('\t#' + str(i + 1) + ':', tagList[i])print()input('any key to continue...')
附上结果 :

显然前后两份的结果区别还是很大的,具体原因应该是语料库的原因。不知道 jieba 的语料库如何,但是本人之前写的代码,因为语料库只有40个文本,且均选自同一本书籍,显然文本本身的区别应该就不是很大。对于一些应该作为关键词的词语,可能会因为在这40个文本组成的语料库相似度的问题而导致计算得出的 idf值很大,从而导致算法结果不是很理想。