机器学习实战读书笔记(四):朴素贝叶斯算法

朴素贝叶斯
优点: 在数据较少的情况下仍然有效 可以处理多类别问题
缺点:对输入的数据的准备方式较为敏感
适用数据类型:标称型数据
p1(x,y)>p2(x,y) 那么类别是1
p2(x,y)>p1(x,y) 那么类别是2
贝叶斯决策的核心是选择具有最高概率的决策
朴素贝叶斯分类器通常有两种方式 : 伯努利模型 和 多项式模型
这里采用伯努利实现方式 该实现不考虑词在文档中出现的次数 只考虑是否出现
某种意义上相当于假设词是等权重的

from numpy import *


# 词表到向量的转换函数
def loadDataSet():
    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']]
    classVec = [0,1,0,1,0,1] # 1代表侮辱词汇 # 0代表正常言论
    return postingList,classVec

# 创建词汇表
def createVocabList(dataSet):
    # 创建词汇集合 空集 初始为空集
    vocabSet = set([])
    for document in dataSet:
        # 操作符| 用于取两个集合的并集
        # vocabSet|set(document) 两个词汇集合取并集
        # 将每篇文章中的新词加入到词汇集
        # set集合所有元素不重复
        vocabSet = vocabSet|set(document)
        # 将词汇集转换为list
    return list(vocabSet)

# 词集模型 只考虑单词是否出现
# vocabList:词汇表
# inputSet:某个文档向量
def setofWords2Vec(vocabList,inputSet):
    # 创建一个其中所含元素都为0的向量
    returnVec = [0]*len(vocabList)
    # 输入集合中的词汇如果出现在词汇表中 定影向量位置设置为1
    for word in inputSet:
        if word in vocabList:
            # vocabList.index(word) 找到word所在的索引值
            # 因为vocabList是从set集合转换过来所以每次只改变一个0
            returnVec[vocabList.index(word)] = 1
        else:
            print('The word: %s is not in my Vocabulary!'%word)
    return returnVec

# 朴素贝叶斯词袋模型
# 每个词是否出现作为一个特征 这可以作为词集模型 伯努利模型
# 如果一个词不仅出现一次 是这个词是否出现不能表达的信息 被称为 词袋模型 多项式模型
# 对setofWords2Vec()进行修改

def bagofWords2VecMN(vocabList, inputSet):
    returnVec = [0]*len(vocabList)
    for word in inputSet:
        if word in inputSet:
            # 该词汇出现自动加一
            returnVec[vocabList.index(word)] += 1
    return returnVec


# 朴素贝叶斯分类器训练函数
# trainMatrix 词向量数据集
# trainCategory 数据集对应的类别标签

# p0Vect:词汇表中各个单词在正常言论中的类条件概率密度
# p1Vect:词汇表中各个单词在侮辱性言论中的类条件概率密度
# pAbusive:侮辱性言论在整个数据集中的比例

def trainNB0(trainMatrix,trainCategory):
    # 训练集总条数
    numTrainDocs = len(trainMatrix)
    # 训练集中的所有不重复单词总数
    numWords = len(trainMatrix[0])
    # 初始化概率 计算属于侮辱性文档 class = 1 的概率,p(1)
    # p(0) = 1-p(1) 二分类 多于两类需要修改
    # 侮辱类占总数的比例
    pAbusive = sum(trainCategory)/float(numTrainDocs)
    # 正常言论的类条件概率密度p(某单词|正常言论)=p0Num/p0Denom
    p0Num = zeros(numWords)
    # 侮辱性言论的类条件概率密度 p(某单词|侮辱性言论)=p1Num/p1Denom
    p1Num = zeros(numWords)
    # 初始化分母置为0
    p0Denom = 0.0
    p1Denom = 0.0
    for i in range(numTrainDocs):
        # 以下是向量相加
        if trainCategory[i] == 1:
            # 如果该篇文章是侮辱性的
            # 统计侮辱类所有文档中的各个单词总数
            p1Num += trainMatrix[i]
            # p1Denom侮辱类总单词数
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])

    # 词汇表中的单词在侮辱性言论文档中的类条件概率
    p1Vect = p1Num/p1Denom
    # 词汇表中的单词在正常性言论文档中的类条件概率
    p0Vect = p0Num/p0Denom
    return p0Vect , p1Vect , pAbusive


# 利用贝叶斯分类器对文档进行分类时,要计算多个概率的乘积以获取某个文档属于某个类别的概率
# 即计算p(w0|1)*p(w1|1)p(w2|1)
# 若其中有一个概率值为0,最后乘积为零 为降低这种影响
# 可以把所有词的出现初始化为1,并将分母初始化为2
# 大部分相乘因子很小,所以程序会下溢出,四舍五入得到0,所以对乘积取自然对数
# ln(a*b) = ln(a)+ln(b) 避免下溢出或者浮点数舍入导致错误 同时采用自然对数不会有任何损失
# 修改trainNB0

def trainNB1(trainMatrix, trainCategory):
    numTrainDocs = len(trainMatrix)
    numWords = len(trainMatrix[0])
    pAbusive = sum(trainCategory) / float(numTrainDocs)
    # 修改初试值
    p0Num = ones(numWords)
    p1Num = ones(numWords)
    p0Denom = 2.0
    p1Denom = 2.0
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            p1Num += trainMatrix[i]
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num += trainMatrix[i]
            p0Denom += sum(trainMatrix[i])
    # 取自然对数
    p1Vect = log(p1Num / p1Denom)
    p0Vect = log(p0Num / p0Denom)
    return p0Vect, p1Vect, pAbusive


# 朴素贝叶斯分类函数
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + 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中
        trainMat.append(setofWords2Vec(myVocabList, postinDoc))
    # 训练分类器
    p0V, p1V, pAb = trainNB1(array(trainMat),array(listClasses))
    testEntry = ['love','my','dalmation']
    thisDoc = array(setofWords2Vec(myVocabList, testEntry))
    print(testEntry, 'classified as: ',classifyNB(thisDoc, p0V, p1V, pAb))
    testEntry = ['stupid', 'garbage']
    thisDoc = array(setofWords2Vec(myVocabList,testEntry))
    print(testEntry, 'classified as: ', classifyNB(thisDoc, p0V, p1V, pAb))

listOPosts , listClasses = loadDataSet()
myVocabList = createVocabList(listOPosts)

# 文件解析及完整的垃圾邮件测试函数
# 1
# print(myVocabList)
# print(setofWords2Vec(myVocabList,listOPosts[0]))
# print(setofWords2Vec(myVocabList,listOPosts[3]))

# 2
# trainMat = []
# for postinDoc in listOPosts:
#     trainMat.append(setofWords2Vec(myVocabList, postinDoc))
# p0V, p1V, pAb = trainNBO(trainMat, listClasses)
# print(pAb)
# print(p0V)
# print(p1V)


# 3
testingNB()

# 4
# 使用朴素贝叶斯对电子邮件进行分类

# 准备数据 切分文本
mySent = 'This book is the best book on python or M.L. I have ever laid eyes upon.'
import re
regEx = re.compile('\W')
listOgTokens = regEx.split(mySent)

# 去除空字符串
# list1 = [tok for tok in listOgTokens if len(tok) > 0]

# 去除空字符串同时全部转化为小写
# tok.upper()
# tok.lower()
# list2 = [tok.lower() for tok in listOgTokens if len(tok) > 0]

# print(listOgTokens)
# print(list1)
# print(list2)


# emailText = open('email/ham/6.txt').read()
# listOgTokens = regEx.split(emailText)
# listText = [tok.lower() for tok in listOgTokens if len(tok) > 2]
# print(listText)

# 测试算法 使用朴素贝叶斯进行交叉验证
# 留存交叉验证: 随机选择数据的一部分作为训练集,剩余部分作为测试集的过程
# 文件解析及完整的垃圾函数测试函数
def textParse(bigString):
    import re
    listOgTokens = re.split(r'\W',bigString)
    return [tok.lower() for tok in listOgTokens if len(tok) >2]

def spamTest():
    # 词汇列表 1*n列 1维数组
    docList = []
    # 结果列表 1*n列 1维数组 0:正常 1:垃圾邮件
    classList = []
    # 二维数组 存放邮件 和结果列表一一对应
    fullText = []
    # 填充三个列表
    for i in range(1,26):
        wordList = textParse(open('email/spam/%d.txt'%i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList = textParse(open('email/ham/%d.txt'%i).read())
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    # 词汇列表去重取并集
    vocabList = createVocabList(docList)
    # 为每封邮件编号
    trainingSet = list(range(50))
    testSet = []

    # 50个邮件随机分成2组,一组10个,一组40个 用于测试和训练
    for i in range(10):
        # 随机选取10个下标放入到testSet内
        # 从训练下标集合中删除
        randIndex = int(random.uniform(0,len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        del(trainingSet[randIndex])
    # 根据trainingSet组成trainMat矩阵 为2维
    trainMat = []
    # 训练邮件结果
    trainClasses = []
    for docIndex in trainingSet:
        trainMat.append(setofWords2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V, p1V, pSpam = trainNB0(array(trainMat),array(trainClasses))
    errorCount = 0
    for docIndex in testSet:
        wordVector = setofWords2Vec(vocabList,docList[docIndex])
        if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
            errorCount += 1
    print('the error rate is: ',float(errorCount)/len(testSet))


spamTest()

email数据集下载地址:

https://download.csdn.net/download/cx_mors/10782081 

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值