版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ArrowLLL/article/details/66974705
引入
信息内容安全课杨老师讲了一个tf-idf算法,用于提取一篇文档的关键词。觉得蛮好玩又正好练习python,所以就试着写了一下,特此记录,各位看官请轻拍板砖。
tf-idf 算法及其原理
偷个懒,直接贴维基百科的解释:
至于原理,同样贴图(没错,我就这么懒了怎么样吧。。→_→) :
如果看维基还是了解不清楚的话,推荐阮一峰大神的博客,这个也是我们的老师上课讲的东西。
至于其中的数学原理,从维基的原理就很容易看出来,基础还是“贝叶斯定理”,另外一点就是idf的值这里使用到了熵的概念。推荐这篇博客的介绍 : TF-IDF模型的概率解释
(少壮不努力, 老大学数学。。。囧rz)
实践准备
操作系统 : ubuntu16.04
python版本 :python3.5.2
引入的python组件 :
- jieba – 用于中文分词,jieba分词组件组件介绍, 可以通过
sudo pip3 install jieba3k
直接安装 - numpy, 科学计算库,通过
sudo pip3 install numpy
安装 - scipy, 科学计算库 + 1,, 通过
sudo pip3 install scipy
安装 - scikit-learn, 数据挖掘库, 可以通过
sudo pip3 install scikit-learn
安装
语料库准备, 努努书坊-鲁迅-伪自由书 。当然是用爬虫爬喽~
爬虫爬取语料库
如果对爬虫理解有问题可参考本人之前的博客 —— 第一个爬虫:爬去古诗中带‘月’的诗句 。爬去的方法并没有很大的改进 (太弱只能写基础的。。。orz)
三步走 :
- 分析之前给出的鲁迅-伪自由书, 获得《伪自由书》中所有文章的链接,并存入一个list ;
- for循环遍历链接list, 从新的url获得《伪自由书》中的文章 ;
- 将获得的文章存入一个文件夹。
附上代码
#!usr/bin/python3
#coding=utf-8
import re
import os
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
def geturl(url):
try :
html = urlopen(url)
except HTTPError as e :
return None
try :
bsObj = BeautifulSoup(html, 'lxml')
except AttributeError as e :
return None
return bsObj
def 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 的文件夹 。
爬去的结果如下:
然后是爬取结果的一部分 :
tf-idf算法实现
仍然是三步走 :
- 使用jieba给所有的文章分词;
- 使用sklearn(即 scikit-learn模块) 中的
CountVectorizer()类
和TfidfTransformer()类
完成对词语的词频分析并获得每篇文章对应的词语的idf值, 可参考[python] 使用scikit-learn工具计算文本TF-IDF值这篇文章的第三部分; - 设定关键字个数,取出每篇文章中tf-idf值最大的值作为对应文章的关键词
先附上代码,然后作说明 :
#coding: utf-8
import os
import jieba
import jieba.posseg as pseg
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
path = './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, ' : ')
weightlist = weight.tolist()
for i in range(n) :
loc = weightlist.index(max(weightlist))
print('\t#' + str(i + 1) + ':', words[loc])
del weightlist[loc]
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 个为止。
最终结果展示
以上です~