机器学习实战 朴素贝叶斯篇

import numpy as np
from math import *
import random


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




#构建词汇表生成函数creatVocabList
def createVocabList(dataSet):
    vocabSet=set([])
    for document in dataSet:
        vocabSet=vocabSet|set(document) #取两个集合的并集
    return list(vocabSet)




#对输入的词汇表构建词向量
#词集模型
def setOfWords2Vec(vocabList,inputSet):
    returnVec=np.zeros(len(vocabList)) #生成零向量的array
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]=1 #有单词,则该位置填充0
        else: print('the word:%s is not in my Vocabulary!'% word)
    return returnVec #返回全为0和1的向量




#这种构建词向量的方法,只记录了每个词是否出现,而没有记录词出现的次数,这样的模型
#叫做词集模型,如果在词向量中记录词出现的次数,每出现一次,则多记录一次,这样的词向
#量构建方法,被称为词袋模型,下面构建以一个词袋模型的词向量生成函数bagOfWord2VecMN:
#词袋模型
def bagOfWords2VecMN(vocabList,inputSet):
    returnVec=[0]*len(vocabList)
    for word in inputSet:
        if word in vocabList:
            returnVec[vocabList.index(word)]+=1
    return returnVec #返回非负整数的词向量






def trainNB0(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)  #文档数目,此例为6
    numWord=len(trainMatrix[0])  #词汇表词数目,即不重复词汇的总和
    pAbusive=sum(trainCategory)/len(trainCategory)  #p1,出现侮辱性评论的概率
    p0Num=np.zeros(numWord)
    p1Num=np.zeros(numWord)
    p0Demon=0;p1Demon=0
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i]  #向量相加,该向量长度为词汇表词数目
            p0Demon+=sum(trainMatrix[i])  #该向量中数值1的累加求和
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    p0Vec=p0Num/p0Demon   #p0/1Vec 向量长度为词汇表词数目,值为词汇表中每个词在
                          #正常/侮辱言论中所有词个数所占的比例
    p1Vec=p1Num/p1Demon
    return p0Vec,p1Vec,pAbusive


##算法漏洞: 
##1.乘积为0 
##我们看到,当某分类下某词项出现频次为0时,其概率也是0,因此在计算p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)
##会因为其中某个的概率为0而全部是0。 为了避免这样的情况发生,我们将所有词项出现的频次都初始化为1,
##某类所有词项数量初始化为2。
##2.因子太小导致结果溢出问题 
##由于p(w0|ci)p(w1|ci)p(w2|ci)......p(wN|ci)中每个因子都很小,所有因子相乘,特别是因子数量多的时候,
##会导致结果溢出,从而得到错误的数据 避免溢出问题的发生,可以使用求自然对数的方法,自然对数和原本
##的数值同增同减,不会有任何损失,因此不会影响求得的概率结果。




def classifyNB(vec2Classify,p0Vec,p1Vec,pClass1):
    p1=sum(vec2Classify*p1Vec)+log(pClass1) #p1=sum(vec2Classify*p1Vec)+log(pClass1) 的数学原理是ln(a*b)=ln(a) +ln(b)
    p0=sum(vec2Classify*p0Vec)+log(1-pClass1)
    if p1>p0:
        return 1
    else:
        return 0


def trainNB1(trainMatrix,trainCategory):
    numTrainDocs=len(trainMatrix)
    numWord=len(trainMatrix[0])
    pAbusive=sum(trainCategory)/len(trainCategory)
    p0Num=ones(numWord);p1Num=ones(numWord)# 初始化为1
    p0Demon=2;p1Demon=2 #初始化为2
    for i in range(numTrainDocs):
        if trainCategory[i]==0:
            p0Num+=trainMatrix[i]
            p0Demon+=sum(trainMatrix[i])
        else:
            p1Num+=trainMatrix[i]
            p1Demon+=sum(trainMatrix[i])
    p0Vec=log(p0Num/p0Demon) #对结果求对数
    p1Vec=log(p1Num/p1Demon) #对结果求自然对数
    return p0Vec,p1Vec,pAbusive






#获取频率最高的词项
def calcMostFreq(vocabList,fullText):
    import operator
    freqDict={}
    for word in vocabList:
        freqDict[word]=fullText.count(word)
    sortedFreq=sorted(freqDict.items(),key=operator.itemgetter(1),reverse=True) #reverse=True/False 降序/升序
    return sortedFreq[:30]  #operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为一些序号(即需要获取的数据在对象中的序号)




def localWords(feed1,feed0):
    import feedparser
    docList=[];classList=[];fullText=[]
    minLen=min(len(feed1['entries']),len(feed0['entries']))
    print(minLen)
    for i in range(minLen):
        wordList=textParser(feed1['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(1)
        wordList=textParser(feed0['entries'][i]['summary'])
        docList.append(wordList)
        fullText.extend(wordList)
        classList.append(0)
    vocabList=createVocabList(docList)
    top30words=calcMostFreq(vocabList,fullText) #选取频率最高的30个词
    #去掉出现频率最高的30个词
    for pairW in top30words:
        if pairW[0] in vocabList:
            vocabList.remove(pairW[0])
    trainSet=list[range(2*minLen)]
    testSet=[]
    print(trainSet)
    for i in range(20):   #从原始数据中选出20个作为测试数据
        randIndex=int(random.uniform(0,len(trainSet)))
        testSet.append(trainSet[randIndex])
        del(trainSet[randIndex])
    trainMat=[];trainClasses=[]
    for docIndex in trainSet:
        trainMat.append(bagOfWords2VecMN(vocabList,docList[docIndex]))
        trainClasses.append(classList[docIndex])
    p0V,p1V,pSpam=trainNB1(trainMat,trainClasses)
    errorCount=0
    for docIndex in testSet:
        wordVector=bagOfWords2VecMN(vocabList,docList[docIndex])
        if classifyNB(wordVector,p0V,p1V,pSpam) !=classList[docIndex]:
            errorCount+=1
    print('the error rate is:',float(errorCount)/len(testSet))
    return vocabList,p0V,p1V




#最具表征性的词汇表显示函数
def getTopWords(ny,sf,t=-6.0):
    import operator
    vocabList,p0V,p1V=localWords(ny,sf)
    topNY=[];topSF=[]
    for i in range(len(p0V)):
    #选取一个阈值t
        if p0V[i]>t:topSF.append((vocabList[i],p0V[i]))
        if p1V[i]>t:topNY.append((vocabList[i],p1V[i]))
    sortedSF=sorted(topSF,key=lambda x: x[1],reverse=True)
    print('SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF')
    for item in sortedSF:
        print(item[0])        
    sortedNY=sorted(topNY,key=lambda pair: pair[1],reverse=True)
    print('NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY')
    for item in sortedNY:
        print(item[0])











你可能感兴趣的:(ML)