#_*_ coding=UTF-8 _*_import osimport randomfrom numpy import*import math
函数声明:朴素贝叶斯新闻分类器训练函数
变量声明:
train_data: 文档特征向量
train_class: 文档类的特征集
numtrain: 训练集的总文件数目
numwords: 矩阵每行占据的长度
myclass: 类名称的列表
pn: 每一个类中每一个词的数目
ps: 该类的单词总数
返回值类型:
pi = [] 类别i的出现概率
pw=[] 类别下各个特征词的频率
def trainNB(train_data, train_class):numtrain = len(train_data)#总文件数numwords = len(train_data[0]) #总单词数p1=p2=p3=p4=p5=p6=p7=p8=p9=ones(numwords) #分子数+1,拉普拉斯平滑处理sum1=sum2=sum3=sum4=sum5=sum6=sum7=sum8=sum9=9.0 #分母数加9,拉普拉斯平滑处理num1=num2=num3=num4=num5 =num6=num7=num8=num9=0#各类文档数目初始为0pn=array([p1,p2,p3,p4,p5,p6,p7,p8,p9])ps=array([sum1,sum2,sum3,sum4,sum5,sum6,sum7,sum8,sum9])classnum=array([num1,num2,num3,num4,num5,num6,num7,num8,num9])myclass=["财经","房产","健康","教育","军事","科技","体育","娱乐","证券"]for i in range(numtrain): #遍历每篇训练文档for j in range(9):#遍历每个类别if train_class[i] == myclass[j]: #如果在类别下的文档pn[j]+=train_data[i]#统计该类每一个词的数目ps[j] += sum(train_data[i]) #计算该类下的单词数目,用于计算特征集中每一个词在yi中的概率classnum[j] +=1#该类文档数目加1breakpw,pi = [],[]for i in range(9): pw.append(pn[i]/ps[i]) #每一个类中单词出现的概率pi.append(classnum[i] / float(numtrain)) #类别的先验概率return pw, pi
函数声明:朴素贝叶斯的测试函数
变量声明:
test_data: 测试集向量
pw 每一个类中某一单词出现的概率
maxclass: 文档分类到各类的概率值列表
pi 各类出现的概率
返回值:
myclass[i]: 返回该测试数据属于哪一个类别
def classNB(test_data, pw,pi):#文档分类到各类的概率值列表maxclass=[]for x in range(9):#乘法计算词频累加得到P(xi|C)总和summ=0for i in range(len(test_data)):if test_data[i]!=0:summ+=math.log(test_data[i]*pw[x][i],10)maxclass.append(summ + math.log(pi[x],10))myclass = ["财经","房产","健康","教育","军事","科技","体育","娱乐","证券" ] #分类集合i=0for x in range(9):if maxclass[i]<maxclass[x]:i=xreturn myclass[i]
函数声明:根据最后的单词表/final_words将文本向量化
变量说明:
train_data: 训练集数据
test_data: 测试集数据
final_words: 特征集数据
返回值说明:
final_train_data: 训练集向量化列表
final_test_data: 测试集向量化列表
def DataVectoring(train_data,test_data,final_words):def TF(text, final_words): #计算向量值,出现在特征集中为1不然为0text_set=set(text)returnVec = [1 if word in text_set else 0 for word in final_words]return returnVecfinal_train_data=[TF(text, final_words) for text in train_data]final_test_data=[TF(text, final_words) for text in test_data]return final_train_data, final_test_data #返回结果
函数声明: 数据的读入和处理
变量说明
news_toot: 新闻文件夹名称
data_list: 数据集
class_list: 数据集类别
train: 训练集
返回值说明
class_data: 所有的单词分类表
everyclassnum:每一类下的文件数目
def TextPrepare(news_toot):folder_list=os.listdir(news_toot) #找到新闻数据下的子文件data_list=[] #数据集数据class_list=[] #数据集的类别for folder in folder_list:new_child_path=os.path.join(news_toot,folder)files=os.listdir(new_child_path)#存放子文件夹下的txt文件for file in range(len(files)): with open(os.path.join(new_child_path,files[file]),"r",encoding="utf-8",errors="ignore") as f:data=f.read()word_list=list(data.split())#将字符串里每一个词提取data_list.append(word_list) #将其放入训练集class_list.append(folder)class_data=list(zip(class_list,data_list)) #数据匹配return class_data
函数说明:获得训练集和测试集并且得到单词表
参数说明:
class_data: 所有的单词分类表
everyclassnum:每一类下的文件数目
变量说明
train: 训练集
返回值说明
train_data: 训练集单词
train_class: 训练集类别
test_data: 测试集单词
test_class: 测试集类别
mywords: 单词及其在训练集对应出现的次数
def GetTrain_Test(class_data):random.shuffle(class_data) #将其乱序index=int(len(class_data)*0.1) #训练集和测试集的划分,每一类只抽取百分之八十test=class_data[0:index] #测试集占比百分之十(每一类抽取百分之八十)train=class_data[index:] #训练集数据占比百分之九十(每一类抽取百分之八十)test_class,test_data=zip(*test) #对测试集解压缩train_class,train_data=zip(*train) #对训练集解压缩words={}#存放所有词的字典for wordlist in train_data: #遍历训练集的数据for word in wordlist:if word in words.keys():#将单词放进我的字典并统计次数words[word] += 1else:words[word] = 1mywords = list(words.items())mywords.sort(key=lambda X:X[1],reverse=True)#对单词表按数目降序排序存储在我的单词表return mywords,train_class,train_data,test_class,test_data #返回我的单词表,训练集类和数据,测试集类和数据
函数说明:读取文件的内容并去重
新闻中出现的很多词语(我们,你们)频率很高,但是
他对新闻的分类没有一点帮助,所以我们将其删除
这类词语称为“停用词”,找到网上的停用词表读取内容
并将我的单词表中的停用词删除
变量名说明:
filename: 停用词表文件名
返回值说明:
stopword: 停用词列表
def StopWord(filename): #获得停用词列表stopword=[]file=open(filename,"r",encoding="utf-8")words=file.read().splitlines()for word in words:if len(word)>0:stopword.append(word)return stopword#获得停用词列表
函数声明:文本特征选取
变量名说明:
deletenum: 删除词频最高的deleten个词
stopwords: 得到的停用词
mywords: 文本中所有的词语
返回值说明:
final_words: 特征集合
def SelWords(mywords,deletenum,stopwords): #获得特征集final_words=[]sum1=0for i in range(deletenum,len(mywords)):if sum1>2000: #训练集大小breakif stopwords.count(mywords[i])==0 and not mywords[i].isdigit() and 1<len(mywords[i]): #如果不是全是数字且不是停用词,那么就放进最终的单词表final_words.append(mywords[i])sum1+=1return final_words
主函数:
if __name__=="__main__":classdata=TextPrepare("new_weibo_13638") #得到数据准备函数的返回值stopwords=StopWord("stop.txt")sum_ratio=0 #正确率for i in range(10): #十次十折交叉验证结果mywords,train_class,train_data,test_class,test_data=GetTrain_Test(classdata)mywordslist,mywordsnum=zip(*mywords)final_words=SelWords(mywordslist,0,stopwords) #获得特征集final_train_data,final_test_data=DataVectoring(train_data,test_data,final_words) #根据词向量模型创建数据的矩阵向量pw,pi=trainNB(array(final_train_data), train_class)yes_sum=0myclass = ["财经","房产","健康","教育","军事","科技","体育","娱乐","证券" ]for test in range(len(test_class)):a=classNB(array(final_test_data[test]),array(pw),array(pi))if(test_class[test]==a):#print(test_class[test],i,len(test_class), '分类结果是: ', classNB(final_test_data[test], pw,pi))yes_sum+=1print("第"+str(i)+"次的正确率为:",yes_sum/len(test_class)) #输出每次的正确率sum_ratio+=yes_sum/len(test_class)print("十次十折后最终的正确率为:",sum_ratio/10) #得到平均的正确率