机器学习实战-【朴素贝叶斯】

本文围绕机器学习中的朴素贝叶斯展开,介绍了实现过程中的难点,如Python集合、list的index()方法等,还提及训练算法中的概率计算及解决下溢出问题的方法。同时阐述了词集和词袋模型,最后给出使用朴素贝叶斯进行文本分类、过滤垃圾邮件及获取区域倾向等应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

机器学习实战-【朴素贝叶斯】

0.总结

'''
对于本例中的二分类

 @ vocabset 统计所有文档中出现的词条列表
 @ returnVec 输入文档转化为词条向量
 
@ pAbusive 所有文档中属于类别 (c1)1 所占的概率 
@ p1Vect   利用NumPy数组计算 p(wi|c1)
@ p0Vect   利用NumPy数组计算p(wi|c0)  

对待分类 vec2Classify 进行比较 p1 和 p2 进行分类
@ vec2Classify
p1 = np.sum(vec2Classify*p1Vec)+np.log(pClass1)
p0 = np.sum(vec2Classify*p0Vec)+np.log(1.0-pClass1)

'''

1.难点说明

1. python中的集合

set是一个无序且不重复的元素集合

利用集合求 交集,并集、、、

2. list中index()方法

index() 函数用于从列表中找出某个值第一个匹配项的索引位置

>>> list_1 = [x for x in range(10,1,-1)]
>>> list_1
[10, 9, 8, 7, 6, 5, 4, 3, 2]
>>> list_1.index(10)
0

3. 训练算法中(trainNB0)

有个词条向量——统计所有文档中出现不重复词的列表(createVocabList())

  1. 计算概率 p ( c i ) p(c_i) p(ci)——类别 i 的文档数 / 总的文档数

    # 所有文档中属于类别 1 所占的概率
    pAbusive = np.sum(trainCategory) / float(numTrainDocs)
    
  2. p ( w 0 , w 1 , w 2 . . w n / c i ) p(w_0,w_1,w_2..w_n/c_i) p(w0,w1,w2..wn/ci) - p1Vect

    #(统计类别为 i 的词条向量中各个词条出现的此次 / 类别为 i 中所有词条的总数)
    p1Vect=p1Num/p1Denom  # i=1
    
  3. 需要计算多个概率的乘积

    • p ( w 0 / 1 ) p ( w 1 / 1 ) p ( w 2 / 1 ) p(w_0/1)p(w_1/1)p(w_2/1) p(w0/1)p(w1/1)p(w2/1)——如果其中一个概率值为0,后面的也为0

    • 降低这种影响,采用拉普拉斯平滑,在分子上添加a(一般为1),分母上添加ka(k表示类别总数),即在这里将所有词的出现数初始化为1,并将分母初始化为2*1=2

    p0Num=ones(numWords);p1Num=ones(numWords)
    p0Denom=2.0;p1Denom=2.0
    
  4. 解决下溢出问题

    p ( w 0 / 1 ) p ( w 1 / 1 ) p ( w 2 / 1 ) p(w_0/1)p(w_1/1)p(w_2/1) p(w0/1)p(w1/1)p(w2/1)——很多很小的数相乘时,最后相乘的结果四舍五入为0

    解决——对乘积取对数

    p0Vect=np.log(p0Num/p0Denom);p1Vect=np.log(p1Num/p1Denom)
    

4.词集模型和词袋模型

词集模型(set-of-words)——每个词的出现与否作为一个特征

词袋模型(bag-of-words)——在词袋中每个单词可以出现多次

def setOfWords2Vec(vocabSet, inputSet):
    '''
    将输入文档转化为词条向量
    '''
    # 新建一个长度为vocabset的列表,并且各维度元素初始化为0
    returnVec = [0]*len(vocabSet)
    # 遍历文档中的每一个词条
    for word in inputSet:
        if word in vocabSet:
            returnVec[vocabSet.index(word)] = 1  # 通过列表获取当前word的索引(下标)
        else: print('the word: %s is not in my vocabulary! '%'word')        
    return returnVec

# 朴素贝叶斯词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
    #词袋向量
    returnVec=[0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            # 区别于词集模型—每遇到一个单词,会增加词向量中对应的值
            returnVec[vocabList.index(word)]+=1    
    return returnVec

5.准备数据(切分文本)

  1. string.split()

    def textParse(bigString):
        '''
        处理文本
        1.以除单词和数字之外的任意符号串,对字符串进行分割
        2.将大写变为小写,并只保留长度大于2的单词
        '''
        listOfTokens = re.split(r'\W+', bigString)  # 分割后有空格
        return [tok.lower() for tok in listOfTokens if len(tok)>2]  
    
  2. 占位符

    open('email/spam/%d.txt' % i).read()
    
    %s字符串占位符。%ns表示字符串的截取,%4s表示截取4位字符串。
    %d数字占位符。
    %f浮点数、小数占位符。(默认会保留6位小数)
    保留两位小数可以用%.2f
    保留两位小数可以用%.3f
    

2.使用朴素贝叶斯进行文本分类

2.1伪代码

计算每个类别中的文档数目
对每篇训练文档:
	对每个类别:
		如果词条出来再文档中 —> 增加该词条的计数值
		增加所词条的计数值
对每个类别:
	对每个词条
		将该词条的数目除以总词条数目得到条件概率
返回每一个类别的条件概率

2.2训练算法

import numpy as np

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'],
                 ['my','licks','ate','my','steak','how', 'to','stop','him'],
                 ['quit','buying','worthless','dog','food','stupid']]
    #由人工标注的每篇文档的类标签
    classVec=[0,1,0,1,0,1]
    return postingList,classVec

def createVocabList(dataSet):
    '''
    统计所有文档中出现的词条列表
    '''
    # 新建一个存放词条的集合
    vocabset = set([])
    for document in dataSet:
        vocabset = vocabset | set(document)  # 去并集
   
    return list(vocabset)   # 将集合转化为列表

def setOfWords2Vec(vocabSet, inputSet):
    '''
    将输入文档转化为词条向量
    '''
    # 新建一个长度为vocabset的列表,并且各维度元素初始化为0
    returnVec = [0]*len(vocabSet)
    # 遍历文档中的每一个词条
    for word in inputSet:
        if word in vocabSet:
            returnVec[vocabSet.index(word)] = 1  # 通过列表获取当前word的索引(下标)
        else: print('the word: %s is not in my vocabulary! '%'word')        
    return returnVec

def trainNB0(trainMatrix, trainCategory):
    '''
    训练算法
    @ trainMatrix    文档矩阵(将文档转化为词列表的矩阵)
    @ trainCategory  类别标签
    '''
    numTrainDocs = len(trainMatrix)  #获取文档中 文档的数目
    numWords = len(trainMatrix[0])  # 获取词条向量的长度(list(vocabset)的长度)
    # 所有文档中属于类别 1 所占的概率
    pAbusive = np.sum(trainCategory) / float(numTrainDocs)
    # 创建一个长度为词条向量等长的列表
    p0Num = np.ones(numWords);p1Num=np.ones(numWords)
    p0Denom=2.0;p1Denom=2.0
    
    for i in range(numTrainDocs):
        if trainCategory[i] == 1:
            #统计所有类别为1的词条向量中各个词条出现的次数
            p1Num += trainMatrix[i]
            #统计类别为1的词条向量中出现的所有词条的总数
            p1Denom += sum(trainMatrix[i])
        else:
            p0Num+=trainMatrix[i]
            p0Denom+=sum(trainMatrix[i])
        
    #利用NumPy数组计算p(wi|c1)
    p1Vect=np.log(p1Num/p1Denom)  
    #利用NumPy数组计算p(wi|c0)
    p0Vect=np.log(p0Num/p0Denom) 
    return p0Vect,p1Vect,pAbusive 
            

if __name__=='__main__':
    listOPosts, listClass = loadDataSet()
    myVocalList = createVocabList(listOPosts)
    
    trainMat = []
    for postiDoc in listOPosts:
        trainMat.append(setofWords2Vec(myVocalList, postiDoc))
    p0v, p1v, pAb = trainNB0(trainMat, listClass)
    
    print(p0v)    
    print(setofWords2Vec(myVocalList, listOPosts[0]))
    print(myVocalList)
['posting', 'worthless', 'my', 'garbage', 'has', 'food', 'park', 'how', 'licks', 'problems', 'take', 'him', 'buying', 'dog', 'help', 'love', 'flea', 'stop', 'so', 'not', 'steak', 'is', 'ate', 'I', 'dalmation', 'please', 'maybe', 'to', 'stupid', 'cute', 'quit']

2.3测试算法(bayes_1.py)

import numpy as np
import bayes

def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    '''
    朴素贝叶斯分类器
    @ vec2Classify  待分类的词条向量
    @ p0Vec 类别1所有文档中各个词条出现的频数p(wi|c1)
    @ pClass1 类别为1的文档占文档总数比例
    '''
    #根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率
    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 = bayes.loadDataSet() # 获取数据集 和 标签
    # 创建词条列表
    myVocabList = bayes.createVocabList(listOPosts)
    ''' 将文档根据 词条列表  转化为 向量'''
    trainMat=[]
    for postinDoc in listOPosts:
        trainMat.append(bayes.setOfWords2Vec(myVocabList,postinDoc))
    # 得到概率值
    p0V,p1V,pAb=bayes.trainNB0(np.array(trainMat),np.array(listClasses))
    '''  测试 
    1. 测试文档
    2. 转化为 向量
    3. 利用分类函数
    '''
    testEntry=['love','my','dalmation']
    thisDoc=np.array(bayes.setOfWords2Vec(myVocabList,testEntry))
    print(testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))  
if __name__=='__main__':
    testingNB()
['love', 'my', 'dalmation'] classified as: 0

3.示例:使用朴素贝叶斯过滤垃圾邮件(bayes_2.py)

import re
import bayes
import bayes_1
import numpy as np 

def textParse(bigString):
    '''
    处理文本
    1.以除单词和数字之外的任意符号串,对字符串进行分割
    2.将大写变为小写,并只保留长度大于2的单词
    '''
    listOfTokens = re.split(r'\W+', bigString)  # 分割后有空格
    return [tok.lower() for tok in listOfTokens if len(tok)>2]  

def spamTest():
    docList = [];classList = [];fullTest = []
    
    for i in range(1,26):
        # 对标签为1的文件进行处理
        wordList=textParse(open('./email/spam/%d.txt' % i).read()) # %d 数字占位符
        docList.append(wordList)
        fullTest.extend(wordList)  #将字符串的元素添加到fullTest
        classList.append(1)
        
        # 类别为0的文件进行处理
        wordList=textParse(open('./email/ham/%d.txt' % i).read())
        docList.append(wordList)
        fullTest.extend(wordList)
        classList.append(0)
        
    vocabList = bayes.createVocabList(docList) #创建字符串列表 
    #构建一个大小为50的整数列表和一个空列表
    trainingSet=list(range(50));testSet=[]
    '''随机选取1~50中的10个数,作为索引,构建测试集'''
    for i in range(10):
        randIndex = int(np.random.uniform(0, len(trainingSet)))
        testSet.append(trainingSet[randIndex])
        #从整数列表中删除选出的数,防止下次再次选出
        #同时将剩下的作为训练集
        del(trainingSet[randIndex])
        
    '''对训练集'''
    trainMat=[];trainClasses=[]
    for docIndex in trainingSet:
        trainMat.append(bayes.setOfWords2Vec(vocabList, docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V, p1V, pSpam = bayes.trainNB0(np.array(trainMat), np.array(trainClasses))
    '''测试集'''
    errorCount = 0
    for docIndex in testSet:
        wordVector = bayes.setOfWords2Vec(vocabList, docList[docIndex])
        if bayes_1.classifyNB(np.array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
            errorCount += 1
    print('错误率为:{}'.format(float(errorCount/len(testSet))))

if __name__=='__main__':
    spamTest()
错误率为:0.2

4.示例:使用朴素贝叶斯分类器从个人广告中获取区域倾向(导入RSS源??)

参考

  1. 机器学习实战之朴素贝叶斯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值