使用sklearn实现朴素贝叶斯文本分类

本文使用的python版本为3.4。
使用前需要安装numpy、matplotlib、scipy和scikitlearn,建议直接下载后安装,下载地址为:python包,选择相应的版本下载,注意不要使用最新的python3.5版本,其对scipy的兼容性不稳定,安装容易失败。
此外还用到了结巴分词、joblib等python包,可以直接通过pip安装。

本文源代码及文本数据集下载地址:https://yunpan.cn/cBNAWRhmttart (提取码:d41a)

python源码及处理逻辑如下:

# -*- coding:utf-8 -*- 
'''
Created on 2016年6月25日

@author: lenovo
'''
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import TfidfVectorizer
import os
import re
import random
import jieba
import joblib
from tokenize import Ignore
class NBclassifier():
    def __init__(self,clf_path=None,vec_path=None):
        '''
        创建对象时完成的初始化工作,判断分类器与vector路径是否为空,
        若为空则创建新的分类器与vector,否则直接加载已经持久化的分类器与vector。
        '''
        if (clf_path==None or vec_path==None):
            self.clf=MultinomialNB()
            self.vec=TfidfVectorizer()
        else:
            self.clf=joblib.load(clf_path)
            self.vec=joblib.load(vec_path)

    #保存模型
    def saveModel(self,clf_path="../../datasets/trainModel/clf.m",vec_path="../../datasets/trainModel/vec.m"):
        joblib.dump(self.clf,clf_path)
        joblib.dump(self.vec,vec_path)

    #从文件夹中加载文本
    def loadTexts(self,textPath):
        dirList=os.listdir(textPath)
        dataList=[]
        labelList=[]
        for dir in dirList:
            fileList=os.listdir(textPath+'/'+dir)
            for filename in fileList:
                    line=open(textPath+u'/'+dir+u'/'+filename,encoding='gb18030',errors='ignore').read()
                    line=re.sub(u'\t|\n',u'',line)
                    if line!=u'':
                        dataList.append(line)
                        labelList.append(dir)
#                     print(filename)
        dataList=self.jiebaSplit(dataList)
        return dataList,labelList

    #载入数据集
    def loadData(self,dataPath):
        dataList=[]
        labelList=[]
        for line in open(dataPath,encoding='utf-8').readlines():
            lineArray=line.split('||')
            if(len(lineArray)==2):
                labelList.append(lineArray[0])
                dataList.append(lineArray[1])
        print('长度是{0}'.format(len(dataList)))
        return dataList,labelList


    #随机生成训练样本与测试样本
    def generateSample(self,dataList,labelList,trainPath,testPath):
            #取30%作为测试集
            RATE=0.3
            listLen=len(dataList)
            testLen=int(RATE*listLen)
            trainDir=open(trainPath,'w',encoding='utf-8')
            testDir=open(testPath,'w',encoding='utf-8')
            indexList=random.sample([i for i in range(listLen)],listLen)

            for item in indexList[:testLen]:
                testDir.write(labelList[item]+'||'+dataList[item])
                testDir.write('\n')
                testDir.flush()
            for item in indexList[testLen:]:
                trainDir.write(labelList[item]+'||'+dataList[item])
                trainDir.write('\n')
                trainDir.flush()


    #结巴分词
    def jiebaSplit(self,data):
        result=[]
        #首先利用结巴分词
        for content in data:
            line=' '.join(jieba.cut(content))
            result.append(line)
        return result

    #训练数据
    def trainNB(self,dataList,labelList):
    #训练模型首先需要将分好词的文本进行向量化,这里使用的TFIDF进行向量化
        self.clf.fit(self.vec.fit_transform(dataList),labelList)
        self.saveModel()

    #预测数据
    def predictNB(self,dataList,labelList):
        data = self.vec.transform(dataList)
        predictList=self.clf.predict(data)
        return predictList

    #计算准确率
    def calAccuracy(self,labelList,predictList):
        rightCount=0
        if(len(labelList)==len(predictList)):
            for i in range(len(labelList)):
                if(labelList[i]==predictList[i]):
                    rightCount+=1
            print ('准确率为:%s' %(rightCount/float(len(labelList))))


if(__name__=='__main__'):
    #创建NB分类器
    nbclassifier=NBclassifier()
    #数据集地址及生成的训练集与测试集地址
    dataPath=u'../../datasets/answer'
#   trainPath=u'../../datasets/trainsets/trainData.txt'
    testPath=u'../../datasets/testsets/testData.txt'
#    dataList,labelList=nbclassifier.loadTexts(dataPath)
#    nbclassifier.generateSample(dataList, labelList,trainPath,testPath)
    #载入训练集与测试集
    dataList,labelList=nbclassifier.loadData(trainPath)
    testData,testLabel=nbclassifier.loadData(testPath)
    #训练并预测分类正确性
    nbclassifier.trainNB(dataList, labelList)
    predictList=nbclassifier.predictNB(testData, testLabel)
    nbclassifier.calAccuracy(predictList, testLabel)

PS:main函数中如果已经训练好了数据,下次预测就可以将训练过程注释掉,并且在创建NB分类器时通过传入路径将已经训练好的模型加载进来,如nbclassifier=NBclassifier(../../datasets/trainModel/clf.m”,”../../datasets/trainModel/vec.m”)

你可能感兴趣的:(机器学习,自然语言处理)