利用朴素贝叶斯分类算法对搜狐新闻进行分类(python)

数据来源  https://www.sogou.com/labs/resource/cs.php
介绍:来自搜狐新闻2012年6月—7月期间国内,国际,体育,社会,娱乐等18个频道的新闻数据,提供URL和正文信息
格式说明:
<doc>
<url>页面URL</url>
<docno>页面ID</docno>
<contenttitle>页面标题</contenttitle>
<content>页面内容</content>
</doc>
注意:content字段去除了HTML标签,保存的是新闻正文文本

一、数据预处理

  (1)数据中为上述doc标签的集合,并不是标准的xml文件,首先将数据开头和结尾分别加上'<data>'和</data>根标签。

 #-*-coding:utf-8-*-
# 修复xml格式
filePath = 'news_sohusite_xml.dat' #语料路径
fileSeqWordDonePath = 'sougou.xml.parse.txt'# 分词后生成路径
fw=open(fileSeqWordDonePath, 'w', encoding='utf-8')
fw.write('<data>')
with open(filePath, 'r', encoding='gb18030' ) as fileTrainRaw: #python3
for line in fileTrainRaw:
fw.write(line.replace('&','&amp;')) #去除非法字符
fw.write('</data>')
fw.close()

(2)提取数据中的分类信息并统计,按照二级域名分析相应类别

import xml.etree.ElementTree as ET
tree = ET.parse(fileSeqWordDonePath)
root = tree.getroot()
# print(root.tag)
classfiy={}
for child in root:
#print(child.tag, child.text)
url = child.find('url')
url_split=url.text.replace('http://','').split('.')
sohu_index=url_split.index('sohu')
if url_split[sohu_index-1] not in classfiy.keys():
classfiy[url_split[sohu_index-1]]=1
else:
classfiy[url_split[sohu_index-1]]+=1
sorted_classfiy=sorted(classfiy.items(),key=operator.itemgetter(1), reverse=True)#排序
for c in sorted_classfiy:
print(c[0],c[1])

输出结果并分析对应分类:

roll ————滚动新闻
it ————科技
auto ————汽车
news ————新闻
stock ————股票
yule ————娱乐
sports ————体育
business ————财经
health ————健康
learning ————教育
money ————理财
s ————体育视频
book ————图书
women ————女性
fund ————基金
baobao ————母婴
travel ————旅游
cul ————文化
gd ————广东
tv
sh ————上海
goabroad
men media chihe
green
astro
club
gongyi
bschool
korea
games dm
v
campus
tuan
expo2010

选取以下分类进bayes行分类:
it 199871————科技
auto 138576————汽车
stock 52930————股票
yule 50138————娱乐
sports 44536————体育
business 27489————财经
health 23409————健康
learning 13012————教育
money 10616————理财
s 8678————体育视频
book 6532————图书
women 5882————女性
fund 5015————基金
baobao 2693————母婴
travel 2179————旅游

(3)计算互信息,抽取各类中的特征词(对分类具有指示作用的词——增加信息量),统计各分类数量

一个常用的方法是计算文档中的词项t与文档类别c的互信息MI,MI度量的是词的存在与否给类别c带来的信息量。
信息量的计算参考这里(https://www.cnblogs.com/fengfenggirl/p/text_feature_selection.html
计算每个词与与每个分类的互信息,每个类别下,互信息排名前200个单词被保留,将他们加入特征词集合。
根据这里的代码做修改,使用jieba分词,并去除停用词,将新闻数据重新组织,仅保留分类和新闻标题及正文

def get_stopword_set(filename='stop_word.txt'):
a=[]
with open(filename, encoding='utf-8') as trainText:
for line in trainText:
a.append(line.strip())
return sorted(set(a)) lables = ['it','auto','stock','yule','sports','business','health','learning','money','s','book','women','fund','baobao','travel']
def lable2id(lable):
for i in range(len(lables)):
if lable == lables[i]:
return i
raise Exception('Error lable %s' % (lable)) def doc_dict():
'''
构造和类别数等长的0向量
'''
return [0]*len(lables) def mutual_info(N,Nij,Ni_,N_j):
'''
计算互信息,这里log的底取为2
'''
return Nij * 1.0 / N * math.log(N * (Nij+1)*1.0/(Ni_*N_j))/ math.log(2) def count_for_cates(trainText, featureFile):
'''
遍历文件,统计每个词在每个类别出现的次数,和每类的文档数
并写入结果特征文件
'''
docCount = [0] * len(lables)
wordCount = collections.defaultdict(doc_dict)
stopword=get_stopword_set()
#扫描文件和计数
for line in trainText:
if not line.strip():continue
lable,text = line.strip().split('^_^',1)
#print lable,text
index = lable2id(lable) #类别索引
#print index
words = text.split(' ')
for word in words:
if word in stopword :continue
elif word ==' ' :continue
elif word ==' ' :continue
wordCount[word][index] += 1 #每个单词在每个类别中的计数
docCount[index] += 1 #各类别单词计数
#计算互信息值
print(u"计算互信息,提取关键/特征词中,请稍后...")
miDict = collections.defaultdict(doc_dict)
N = sum(docCount)
for k,vs in wordCount.items(): #遍历每个单词
#print 'k,vs', k,vs
#break
for i in range(len(vs)): #遍历每个分类,计算词项k与文档类别i的互信息MI
N11 = vs[i] #类别i下单词k的数量
N10 = sum(vs) - N11 #非类别i下单词k的数量
N01 = docCount[i] - N11 #类别i下其他单词数量
N00 = N - N11 - N10 - N01 #其他类别中非k单词数目
#print N11,N10,N01,N00
mi = mutual_info(N,N11,N10+N11,N01+N11) + mutual_info(N,N10,N10+N11,N00+N10)+ mutual_info(N,N01,N01+N11,N01+N00)+ mutual_info(N,N00,N00+N10,N00+N01)
miDict[k][i] = mi
fWords = set()
for i in range(len(docCount)): #遍历每个单词
keyf = lambda x:x[1][i]
sortedDict = sorted(miDict.items(),key=keyf,reverse=True)
t=','.join([w[0] for w in sortedDict[:20]])
print(lables[i] ,':',t)
for j in range(1000):
fWords.add(sortedDict[j][0])
out = open(featureFile, 'w', encoding='utf-8')
#输出各个类的文档数目
out.write(str(docCount)+"\n")
#输出互信息最高的词作为特征词
for fword in fWords:
out.write(fword+"\n")
print(u"特征词写入完毕...")
out.close() if __name__=="__main__":
# print(get_stopword_set())
_trainText=[]
with open('sohu_train.txt', encoding='utf-8') as trainText:
for line in trainText:
id,catgre,body= line.split('^_^')
#print id,catgre
_trainText.append(catgre+'^_^'+body) #数据打乱分成两份,4/5用来训练,1/5用来测试
random.shuffle(_trainText)
num = len(_trainText)
_testText = _trainText[4*num//5:]
_trainText = _trainText[:4*num//5] # #计算互信息,提取关键字
count_for_cates(_trainText, 'featureFile')

打印每个类别中排名前20的特征词:

PS D:\学习\朴素贝叶斯-文本分类\news_sohusite_xml.full> python3 .\bayes_classfify.py
计算互信息,提取关键/特征词中,请稍后...
it : 系列,CPU,华硕,英寸,尺寸,主频,屏幕,硬盘容量,内存容量,芯片,显卡,Intel,参数,操作系统,型号,产品,Windows,酷睿,NVIDIA
auto : 座椅,mm,调节,系列,CPU,华硕,电动,发动机,L,元,后排,汽车,方向盘,英寸,系统,车型,主频,车,屏幕
stock : 万股,公司,系列,CPU,华硕,公告,股份,证券,英寸,股,尺寸,A股,参数,主频,屏幕,硬盘容量,内存容量,显卡,芯片
yule : 娱乐,讯,电影,系列,CPU,导演,华硕,观众,演员,主演,英寸,产品,拍摄,尺寸,饰演,搜狐,参数,主频,屏幕
sports : 比赛,球队,球员,系列,CPU,华硕,开出,赛季,号码,期,联赛,冠军,英寸,尺寸,产品,球迷,对手,主场,参数
business : 系列,CPU,华硕,经济,市场,英寸,尺寸,主频,参数,屏幕,硬盘容量,内存容量,显卡,芯片,公司,Intel,企业,座椅,型号
health : 本品,治疗,患者,主任医师,处方,看病,大夫,医院,服用,下夜,疾病,剂量,医生,用量,过程,就医,国药准字,应,禁用
learning : 类,专业,考生,第二批,经济学,第一批,录取,高考,学校,学生,招生,教育,第三批,平均分,高校,批次,志愿,科学,电子信息
money : 银行,信托,收益率,投资,理财产品,系列,终止,CPU,华硕,理财,美元,提前,收益,保障,预期,英寸,黄金,尺寸,资产
s : 视频,体育,天下,时间,北京,CBA,集锦,广播节目,收看,轮,西甲,搜狐,破门,VS,赛季,日,系列,联赛,比赛
book : 说,看着,币,系列,原创,想,走,CPU,华硕,凌天,黎涵,道,女人,里,七妹,产品,英寸,尺寸,馥薰
women : 肌肤,肤质,功效,库,制造商,品牌,所属,保湿,官网,商品,精华,男人,CPU,华硕,女人,美白,皮肤,介绍,滋润
fund : 基金,0.00,投资,证券,申购,代销,净值,起始,债券,开放式,代码,指数,费率,收益,股票,有限公司,管理,日常,机构,赎回
baobao : 宝宝,孩子,妈妈,怀孕,胎儿,吃,孕妇,准妈妈,系列,婴儿,发育,父母,幼儿园,CPU,家长,华硕,食物,儿童,营养
travel : 旅游,概述,攻略,位于,景区,简介,温泉,平方公里,系列,米,公里,公园,景点,面积,CPU,,华硕,河南,版友

二、训练模型,计算先验概率,即每个类别下各个单词出现的概率

def load_feature_words(featureFile):
'''
从特征文件导入特征词
'''
f = open(featureFile, encoding='utf-8')
#各个类的文档数目
docCounts = eval(f.readline())
features = set()
#读取特征词
for line in f:
features.add(line.strip())
f.close()
return docCounts,features def train_bayes(featureFile, textFile, modelFile):
'''
训练贝叶斯模型,实际上计算每个类中特征词的出现次数
'''
print(u"使用朴素贝叶斯训练中...")
docCounts,features = load_feature_words(featureFile) #读取词频统计和特征词
wordCount = collections.defaultdict(doc_dict)
# #每类文档特征词出现的次数
tCount = [0]*len(docCounts)
# for line in open(textFile).readlines():
for line in textFile: #遍历每个文档
lable,text = line.strip().split('^_^',1)
index = lable2id(lable)
words = text.strip().split(' ')
for word in words: #遍历文档中每个词
if word in features and word !='':
tCount[index] += 1 #类别index中单词总数计数
wordCount[word][index] += 1 #类别index中单词word的计数
outModel = open(modelFile, 'w', encoding='utf-8')
#拉普拉斯平滑
print(u"训练完毕,写入模型...")
for k,v in wordCount.items(): #遍历每个单词
scores = [(v[i]+1) * 1.0 / (tCount[i]+len(wordCount)) for i in range(len(v))] #遍历每个类别i,计算该类别下单词的出现概率(频率)
outModel.write(k+"\t"+str(scores)+"\n") #保存模型,记录类别i下单词k的出现概率(频率)
outModel.close()
if __name__=="__main__":
# print(get_stopword_set())
_trainText=[]
with open('sohu_train.txt', encoding='utf-8') as trainText:
for line in trainText:
id,catgre,body= line.split('^_^')
#print id,catgre
_trainText.append(catgre+'^_^'+body) #数据打乱分成两份,4/5用来训练,1/5用来测试
random.shuffle(_trainText)
num = len(_trainText)
_testText = _trainText[4*num//5:]
_trainText = _trainText[:4*num//5] # #计算互信息,提取关键字
count_for_cates(_trainText, 'featureFile') #训练,计算先验概率
train_bayes('./featureFile', _trainText, './modelFile')

利用朴素贝叶斯分类算法对搜狐新闻进行分类(python)

三、模型测试,通过贝叶斯公式预测分类,并评价分类精度

def load_model(modelFile):
'''
从模型文件中导入计算好的贝叶斯模型
'''
print(u"加载模型中...")
f = open(modelFile, encoding='utf-8')
scores = {}
for line in f:
word,counts = line.strip().rsplit('\t',1)
scores[word] = eval(counts)
f.close()
return scores def predict(featureFile, modelFile, testText):
'''
预测文档的类标,标准输入每一行为一个文档
'''
docCounts,features = load_feature_words(featureFile) #读取词频统计和特征词
docScores = [math.log(count * 1.0 /sum(docCounts)) for count in docCounts] #每个类别出现的概率
scores = load_model(modelFile) #加载模型,每个单词在类别中出现的概率
rCount = [0]*len(lables)
docCount = [0]*len(lables)
print(u"正在使用测试数据验证模型效果...")
for line in testText:
lable,text = line.strip().split('^_^',1)
index = lable2id(lable)
words = text.split(' ')
preValues = list(docScores)
for word in words:
if word in features and word !='':
for i in range(len(preValues)):
preValues[i]+=math.log(scores[word][i]) #利用贝叶斯公式计算对数概率,后半部分为每个类别中单词word的出现概率
m = max(preValues) #取出最大值
pIndex = preValues.index(m) #取出最大值类别的索引
if pIndex == index: #预测分类正确
rCount[index] += 1
#print lable,lables[pIndex],text
docCount[index] += 1
for r in range(len(lables)):
print(u"类别:%s,测试文本量: %d , 预测正确的类别量: %d, 朴素贝叶斯分类器准确度:%f" %(lables[r],rCount[r],docCount[r],rCount[r] * 1.0 / docCount[r]))
print(u"总共测试文本量: %d , 预测正确的类别量: %d, 朴素贝叶斯分类器准确度:%f" %(sum(rCount),sum(docCount),sum(rCount) * 1.0 / sum(docCount))) if __name__=="__main__":
# print(get_stopword_set())
_trainText=[]
with open('sohu_train.txt', encoding='utf-8') as trainText:
for line in trainText:
id,catgre,body= line.split('^_^')
#print id,catgre
_trainText.append(catgre+'^_^'+body) #数据打乱分成两份,4/5用来训练,1/5用来测试
random.shuffle(_trainText)
num = len(_trainText)
_testText = _trainText[4*num//5:]
_trainText = _trainText[:4*num//5] # #计算互信息,提取关键字
# count_for_cates(_trainText, 'featureFile') #训练,计算先验概率
# train_bayes('./featureFile', _trainText, './modelFile') #预测
predict('./featureFile', './modelFile', _testText)

打印各类的分类精度和总体精度:

正在使用测试数据验证模型效果...
类别:it,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.892501
类别:auto,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.843156
类别:stock,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.588263
类别:yule,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.950451
类别:sports,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.921394
类别:business,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.550701
类别:health,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.956885
类别:learning,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.910860
类别:money,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.695652
类别:s,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.791713
类别:book,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.635542
类别:women,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.709030
类别:fund,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.906641
类别:baobao,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.791513
类别:travel,测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.901099
总共测试文本量: , 预测正确的类别量: , 朴素贝叶斯分类器准确度:0.837472

 参考

http://www.cnblogs.com/fengfenggirl/p/bayes_classify.html

https://blog.csdn.net/han_xiaoyang/article/details/50629608

https://www.cnblogs.com/fengfenggirl/p/text_feature_selection.html

上一篇:k8s-rabbitmq-(一)集群部署


下一篇:[转]c#快捷键