zoukankan      html  css  js  c++  java
  • 《机器学习实战》笔记——朴素贝叶斯

    闲来无事最近复习了一下ID3决策树算法,并凭着理解用pandas实现了一遍,加了些自己的理解(链接如下)。相比本篇博文,更简明清晰,更适合复习用。

    https://github.com/DianeSoHungry/ShallowMachineLearningCodeItOut/blob/master/Naive%20Bayes.ipynb

    第一步:分类器的建立、训练、以及测试

    运用贝叶斯公式(朴素贝叶斯假设每个特征每个特征都是独立的)可以解决的问题有,已知某些特征,用来判断某情况发生的可能性大小,设置可能性最大的情况作为预测值。

    是一种监督算法。

    广泛应用于垃圾邮件检测等等。

      1 # _*_coding:utf-8_*_
      2 from numpy import *
      3 
      4 # 4-1 词表到向量的转换函数(实验样本)
      5 def loadDataSet():
      6     postingList = [['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],
      7                    ['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],
      8                    ['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],
      9                    ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
     10                    ['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],
     11                    ['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]
     12     classVec = [0, 1, 0, 1, 0, 1]  # 1 is abusive, 0 not
     13     return postingList, classVec
     14 
     15 # 返回一个dataSet中所有出现过的词条列表
     16 def createVocabList(dataSet):
     17     vocabSet = set([])
     18     for document in dataSet:
     19         vocabSet = vocabSet | set(document) #用于求两个集合的并集
     20     return list(vocabSet)
     21 
     22 # # 输入参数为词汇表(vocabSet)和某个文档(inputSet),返回的是元素和词汇表元素一一对应的向量returnVec
     23 # # vocabSet中的元素在inputSet中出现过则向量中元素为1,反之为0
     24 def setOfWords2Vec(vocabList, inputSet):
     25     returnVec = [0] * len(vocabList)    # [1,2,3]*3 结果等于[1,2,3,1,2,3,1,2,3]
     26     for word in inputSet:
     27         if word in vocabList:
     28             returnVec[vocabList.index(word)] = 1
     29         else:
     30             print ("the word: %s is not in my Vocabulary!" % word)    # 为什么有这一步?
     31     return returnVec
     32 
     33 # 4-4 朴素贝叶斯词袋模型
     34 # 修改setOfWords2Vec函数
     35 def bagOfWords2Vec(vocabList, inputSet):
     36     returnVec = [0] * len(vocabList)    # [1,2,3]*3 结果等于[1,2,3,1,2,3,1,2,3]
     37     for word in inputSet:
     38         if word in vocabList:
     39             returnVec[vocabList.index(word)] += 1
     40     return returnVec
     41 
     42 # 4-2 朴素贝叶斯分类器训练函数
     43 # 注意:
     44 # trainMatrix不是最原始的文档,而是由原始文档列表得到的矩阵,
     45 # 矩阵的列分别对应了所有出现过的词,行对应了各个不同的句子
     46 # 上面函数的输出returnVec就是trainMatrix其中的一行
     47 # trainCategory为该行是否为侮辱性言论。1为是
     48 def trainNB0(trainMatrix, trainCategory):   #
     49     numTrainDocs = len(trainMatrix) # 有几句话
     50     numWords = len(trainMatrix[0])  # 每句话有几个词条
     51     pAbusive = sum(trainCategory)/float(numTrainDocs)   # trainCategory中元素为1的表示是侮辱性语言
     52     p0Num = zeros(numWords)+0.00000001 # 累计所有非侮辱性言论中,各个词条出现过的次数
     53     p1Num = zeros(numWords)+0.00000001 # 累计所有侮辱性言论中,各个词条出现过的次数 加一个极小量是为了避免在侮辱性言论的条件下,某个词条
     54                                        # 的概率为0的情况,此时,最终结果也会为0,显然不对。
     55     # p0Denom = 0.0   # 书上代码是被我注释掉了,最终是要得到(非)侮辱性言论中所有出现过的词汇的总和(包括重复值),
     56     # p1Demon = 0.0   # 不如在最后将(非)侮辱性言论中每个词汇出现过的次数相加。
     57     for i in range(numTrainDocs):
     58         if trainCategory[i] == 1:
     59             p1Num += trainMatrix[i]
     60             # p1Demon += sum(trainMatrix[i])
     61         else:
     62             p0Num += trainMatrix[i]
     63             # p0Denom += sum(trainMatrix[i])
     64     p1Demon=sum(p1Num)
     65     p0Denom=sum(p0Num)
     66     # p1Vect = p1Num/p1Demon
     67     # p0Vect = p0Num/p0Denom
     68     p1Vect = log(p1Num / p1Demon)   # 利用log()函数避免多个概率连乘过小的问题
     69     p0Vect = log(p0Num / p0Denom)
     70     return p0Vect, p1Vect, pAbusive
     71 
     72 # 4-3 朴素贝叶斯分类函数
     73 # 对于一个测试点,p(ci)几乎不变,p(w|ci)=p(w0|ci)*p(w1|ci)...p(wn|ci)
     74 # 而p(w0|ci)的概率又等于pow( ci发生的条件下,下标为0的特征=1的概率, w0发生的次数)
     75 
     76 def classifyNB(vec2Classify, p0Vec,p1Vec, pClass1):
     77     p1 = sum(vec2Classify * p1Vec) + log(pClass1)
     78     p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
     79     if p1 > p0:
     80         return 1
     81     else:
     82         return 0
     83 
     84 def testingNB():
     85     listOPosts,listClasses = loadDataSet()
     86     myVocabList = createVocabList(listOPosts)
     87     trainMat = []
     88     for postinDoc in listOPosts:
     89         trainMat.append(bagOfWords2Vec(myVocabList, postinDoc))
     90     p0V, p1V, pAb =trainNB0(array(trainMat), array(listClasses))
     91     testEntry = ['love', 'my', 'dalmation']
     92     thisDoc = array(bagOfWords2Vec(myVocabList,testEntry))
     93     print (testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
     94     testEntry = ['stupid','garbage']
     95     thisDoc = array(bagOfWords2Vec(myVocabList,testEntry))
     96     print (testEntry,'classified as:',classifyNB(thisDoc,p0V,p1V,pAb))
     97 
     98 
     99 # 4-5 文件解析及完整的垃圾邮件测试函数
    100 def textParse(bigString):
    101     import re
    102     listOfTokens = re.split(r'W*', bigString)  #正则表达式中W表示w的相反,后者表示的是字母数字下划线,将正则表达式作为split()函数的第一个参数,比表示以此为分隔符
    103     return [tok.lower() for tok in listOfTokens if len(tok) > 2]
    104 
    105 def spamTest():
    106     docList=[]  #共50个元素,每个元素为指向一个文本的引用,有序
    107     classList=[]    #共50个元素,与docList元素一一对应,有序
    108     fullText=[] #把50个文件内容连起来的一个文本文件
    109     for i in range(1,26):   #从第1个txt文件到第25个,依次遍历
    110         wordList = textParse(open('email/spam/%d.txt'%i).read())
    111         docList.append(wordList)
    112         fullText.extend(wordList)
    113         classList.append(1) #spam文件里的标签都为1 ham文件里的标签都为0
    114         wordList = textParse(open('email/ham/%d.txt'%i).read())
    115         docList.append(wordList)
    116         fullText.extend(wordList)
    117         classList.append(0)
    118     vocabList = createVocabList(docList)
    119     trainingSet = range(50) #存储的是docList的下标
    120     testSet=[]  #存储的是docList的下标
    121     for i in range(10):  # 随机选取从训练集里选10个放到测试集
    122         randIndex = int(random.uniform(0,len(trainingSet)))
    123         testSet.append(trainingSet[randIndex])
    124         del(trainingSet[randIndex])
    125     trainMat=[]
    126     trainClasses=[]
    127     for docIndex in trainingSet:
    128         trainMat.append(setOfWords2Vec(vocabList,docList[docIndex]))
    129         trainClasses.append(classList[docIndex])
    130     p0v,p1v,pSpam = trainNB0(array(trainMat), array(trainClasses))
    131
    132     errorCount = 0
    133     for docIndex in testSet:
    134         wordVector = setOfWords2Vec(vocabList, docList[docIndex])
    135         if classifyNB(array(wordVector),p0v,p1v,pSpam) != classList[docIndex]:
    136             errorCount += 1
    137     print"the error rate is: ", float(errorCount) / len(testSet)

    到目前为止,已经建好了一个朴素贝叶斯分类器并用txt文件进行训练和测试。

    第二步:应用——通过婚恋网上的求偶信息判断所在地域

    需要从婚恋网上获得实时信息,这需要RSS阅读器,python中最常用的RSS程序库是Universal Feed Parser。下载、安装。

    在第一步的代码中,继续加入以下代码,并运行。

     1 # 4-6 RSS源分类器及高频词去除函数
     2 
     3 # 从fullText中找vacabList中每个词条出现的次数,选取次数最多的前30项,形成排好序的字典
     4 def calcMostFreq(vocabList, fullText):
     5     import operator
     6     freqDict = {}
     7     for token in vocabList:
     8         freqDict[token] = fullText.count(token)
     9     sortedFreq = sorted(freqDict.iteritems(), key=operator.itemgetter(1),reverse=True)
    10     return sortedFreq[:30]
    11 
    12 # 训练分类器
    13 def localWords(feed1, feed0):   #这里feed1,feed0不是两个不同标签的文本文件的引用,二是指向两个网址
    14     import feedparser
    15     docList=[]  # 最终用来装所有的文章
    16     classList=[]    # docList对应的标签(是哪个网站的)
    17     fullText=[] # 选取的所有文章的词(有重复)
    18     minLen = min(len(feed1['entries']), len(feed0['entries']))  # 为了在两个网站上取相同数量的文章数
    19     for i in range(minLen):
    20         wordList = textParse(feed1['entries'][i]['summary'])    # 把feed1中文章简介给切分成词条列表
    21         docList.append(wordList)
    22         fullText.extend(wordList)
    23         classList.append(1)
    24         wordList = textParse(feed0['entries'][i]['summary'])
    25         docList.append(wordList)
    26         fullText.extend(wordList)
    27         classList.append(0)
    28     vocabList = createVocabList(docList)
    29     top30Words = calcMostFreq(vocabList,fullText)
    30     for pairW in top30Words:    # 删除30个高频词条,据经验这样可以提高预测结果。因为这样可以减小冗余词汇的影响
    31         if pairW[0] in vocabList: vocabList.remove(pairW[0])    # pairW不是一个字符串,而是字典元素。按道理不需要判断的
    32     trainingSet = range(2*minLen)
    33     testSet = []
    34     for i in range(20):
    35         randIndex = int (random.uniform(0, len(trainingSet)))
    36         testSet.append(trainingSet[randIndex])
    37         del(trainingSet[randIndex])
    38     trainMat = []
    39     trainClasses = []
    40     for docIndex in trainingSet:
    41         trainMat.append(bagOfWords2Vec(vocabList, docList[docIndex]))   # 书上这块估计是有排版印刷的问题的
    42         trainClasses.append(classList[docIndex])
    43     p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))
    44     errorCount = 0
    45     for docIndex in testSet:
    46         wordVector = bagOfWords2Vec(vocabList, docList[docIndex])
    47         if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
    48             errorCount += 1
    49     print 'the error rate is: ', float(errorCount)/len(testSet)
    50     return vocabList, p0V, p1V
    51 
    52 import feedparser
    53 ny=feedparser.parse('http://newyork.craigslist.org/stp/index.rss')
    54 print len(ny['entries'])
    55 sf=feedparser.parse('http://sfbay.craigslist.org/stp/index.rss')
    56 print len(sf['entries'])
    57 vocabList, pSF, pNY = localWords(ny,sf)
  • 相关阅读:
    linux seqlock 锁
    linux 位操作
    linux 原子变量
    linux 读者/写者自旋锁
    linux自旋锁函数
    linux 自旋锁 API 简介
    linux Completions 机制
    linux 读者/写者旗标
    linux 在 scull 中使用旗标
    Linux 旗标实现
  • 原文地址:https://www.cnblogs.com/DianeSoHungry/p/7067653.html
Copyright © 2011-2022 走看看