朴素贝叶斯---分类

朴素贝叶斯

import numpy as np
import matplotlib.pyplot as plt
from math import log

文本分类
词表到向量的转换函数

def loadDataSet():
    """
    生成一个文本数据集和标签
    参数:
        无
    返回:
        postingList -- 文本列表
        classVec -- 标签分类
    
    """
    postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
                 ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
                 ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
                 ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                 ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
                 ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
    #0-非侮辱性,1-侮辱性
    classVec = [0,1,0,1,0,1]    
    return postingList,classVec
In [3]:
def createVocabList(dataSet):
    """
    建立词汇表,也就是所有文本的并集
    参数:
        dataSet -- 数据集
    返回:
        vocabSet -- 词汇表
    """
    #首先建立一个空集,新建一个集合,避免直接修改原数据
    vocabSet = set([])
    #遍历数据集中的每个文档
    for document in dataSet:
        #每个文档和之前的词汇表求并集,保证没有重复
        vocabSet = vocabSet | set(document)
    return list(vocabSet)
def setOfWords2Vec(vocabList, inputSet):
    """
    #初始化返回句子向量,长度为词汇表长度的全0向量
    returnVec = [0]*len(vocabList)
    #遍历输入集中的所有词汇
    for word in inputSet:
        #如果该词汇在词汇表中
        if word in vocabList:
            #对应序号元素置1
            returnVec[vocabList.index(word)] = 1
        #反之给出错误提示
        else: 
            print("词汇“{}”不在词汇表中".format(word))
    return returnVec

检验函数的执行效果

listOPosts, listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)
print("myVocabList = {}".format(myVocabList))

结果:

myVocabList = ['how', 'has', 'him', 'stop', 'stupid', 'garbage', 'so', 'not', 'quit', 'flea', 'posting', 'to', 'love', 'steak', 'problems', 'food', 'worthless', 'mr', 'please', 'dalmation', 'maybe', 'take', 'buying', 'dog', 'my', 'I', 'licks', 'cute', 'ate', 'park', 'help', 'is']

从词向量计算概率

def trainNB0(trainMatrix,trainCategory):
    #将数据转换为矩阵形式
    trainData = np.array(trainMatrix)
    trainLabels = np.array(trainCategory)
    #训练文本数
    numTrainDocs = trainData.shape[0]
    #训练词条数
    numWords = trainData.shape[1]
    #侮辱性文本的概率为训练标签取均值
    pAbusive = np.mean(trainLabels)
    #初始化为全1
    p0Num = np.ones((1, numWords)); p1Num = np.ones((1, numWords))
    #分母初始化为2
    #两项改动为了是避免连乘中一项为0,导致整体结果为0的情况
    #Bayes分类只用比较概率的相对大小,所以这么做不会影响结果
    p0Denom = 2.0; p1Denom = 2.0
    #p1Num为统计每个侮辱性词条出现次数的向量,等于文本中标记1的子矩阵,沿axis = 0相加
    p1Num += np.sum(trainData[trainLabels == 1, :], axis = 0, keepdims = True)
    #p1Denom为统计侮辱性词条总数的标量,等于文本中标记1的子矩阵向量之和
    p1Denom += np.sum(trainData[trainLabels == 1, :])
    #p0同上
    p0Num += np.sum(trainData[trainLabels == 0, :], axis = 0, keepdims = True)
    p0Denom += np.sum(trainData[trainLabels == 0, :])
    #对概率取对数,可以避免下溢出或者浮点数舍入误差,同样由于相对大小不变,不影响结果
    p1Vect = np.log(p1Num/p1Denom)
    p0Vect = np.log(p0Num/p0Denom)
    return p0Vect,p1Vect,pAbusive
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    """
    #元素间乘法
    p1 = np.sum(vec2Classify * p1Vec) + np.log(pClass1)
    p0 = np.sum(vec2Classify * p0Vec) + np.log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else: 
        return 0
def testingNB():
    """
    测试朴素贝叶斯分类器
    参数:
        无
    返回:
        无 -- 直接打印结果
    """
    #读取之前的数据
    listOPosts,listClasses = loadDataSet()
    #产生词汇表
    myVocabList = createVocabList(listOPosts)
    #初始化一个训练矩阵
    trainMat=[]
    #遍历文档
    for postinDoc in listOPosts:
        #转化为向量后,添加到训练矩阵中
        trainMat.append(setOfWords2Vec(myVocabList, postinDoc))
    #得到三个概率
    p0V,p1V,pAb = trainNB0(np.array(trainMat),np.array(listClasses))
    #待测试词组
    testEntry = ['love', 'my', 'dalmation']
    #词组转为矩阵
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    #打印结果
    print("{} classified as: {}".format(testEntry, classifyNB(thisDoc,p0V,p1V,pAb)))
    #待测试词组
    testEntry = ['stupid', 'garbage']
    #词组转为矩阵
    thisDoc = np.array(setOfWords2Vec(myVocabList, testEntry))
    #打印结果
    print("{} classified as: {}".format(testEntry, classifyNB(thisDoc,p0V,p1V,pAb)))

测试

testingNB()

结果


['love', 'my', 'dalmation'] classified as: 0
['stupid', 'garbage'] classified as: 1

文档的词袋模型

def bagOfWords2VecMN(vocabList, inputSet):
    """
    文档的词袋模型
    参数:
        vocabList -- 词汇列表
        inputSet -- 输入词集
    返回:
        returnVec -- 返回向量
    """
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            #如果在词库中,对应词条就++
            returnVec[vocabList.index(word)] += 1
    return returnVec

使用朴素贝叶斯过滤垃圾邮件
使用朴素贝叶斯进行交叉验证

def textParse(bigString):
    """
    输入很长的字符串,转换为向量
    参数:
        bigString -- 长字符串
    返回:
        去掉少于两个字符,转换为小写的字符串
    """
    import re
    listOfTokens = re.split(r'\W*', bigString)
    return [tok.lower() for tok in listOfTokens if len(tok) > 2]
def spamTest():
    """
    垃圾邮件测试
    参数:
        无
    返回:
        无
    """
    #新建三个列表
    docList=[]; classList = []; fullText =[]
    #遍历垃圾邮件和正常邮件,各25个
    for i in range(1,26):
        #读取垃圾邮件
        wordList = textParse(open("email/spam/{}.txt".format(i), errors = 'ignore').read())
        #添加到列表
        docList.append(wordList)
        fullText.extend(wordList)
        #添加到类
        classList.append(1)
        #读取正常邮件
        #ham中的23.txt总是报错有不能解读的字节,选择忽略该错误
        wordList = textParse(open("email/ham/{}.txt".format(i), errors = 'ignore').read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    #创建词汇表
    vocabList = createVocabList(docList)
    #训练集和测试集序号集
    trainingSet = list(range(50)); testSet=[]
    #随机抽取训练集中的10个序号,放入测试集
    for i in range(10):
        #生成随机序号
        randIndex = np.int(np.random.uniform(0,len(trainingSet)))
        #序号对应的元素由训练集移动到测试集中
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex]) 
    #新建训练矩阵和训练标签
    trainMat=[]; trainClasses = []
    #对于训练集中的元素
    for docIndex in trainingSet:
        #对应词袋添加到训练矩阵中
        trainMat.append(bagOfWords2VecMN(vocabList, docList[docIndex]))
        #类别添加到标签中
        trainClasses.append(classList[docIndex])
    #训练朴素贝叶斯分类器
    p0V,p1V,pSpam = trainNB0(np.array(trainMat),np.array(trainClasses))
    #错误计数器初始化为0
    errorCount = 0
    #对于测试集
    for docIndex in testSet:
        #得到词袋向量
        wordVector = bagOfWords2VecMN(vocabList, docList[docIndex])
        #判断结果
        if classifyNB(np.array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
            #统计错误
            errorCount += 1
            #打印错误信息
            print("错误序号为:{}".format(docList[docIndex]))
    print("总准确率为:{}".format(1 - np.float(errorCount)/len(testSet)))

测试结果

错误序号为:['oem', 'adobe', 'microsoft', 'softwares', 'fast', 'order', 'and', 'download', 'microsoft', 'office', 'professional', 'plus', '2007', '2010', '129', 'microsoft', 'windows', 'ultimate', '119', 'adobe', 'photoshop', 'cs5', 'extended', 'adobe', 'acrobat', 'pro', 'extended', 'windows', 'professional', 'thousand', 'more', 'titles']
总准确率为:0.9

参考
文章借鉴了同学的优秀作业

猜你喜欢

转载自blog.csdn.net/zx_zhang01/article/details/83065777