基于朴素贝叶斯的图像分类

朴素贝叶斯是一种极其简单的分类算法,通过概率统计到的方式进行判别。通过特征的联合概率分布P(w1,w2,w3,….wn|C)进行建模,进而得到P(C|w1,w2,w3,….wn).进而转换成一种监督分类的算法

贝叶斯公式:
这里写图片描述

目标是根据特征得到属于某一类的概率,哪一类的概率最大则是哪一类。P©根据大数定律,我们通过频率来代替概率。建模关键点还是在于P(W|C)的求解,W为特征向量,则P(W|C)=P(w1,w2,w3,….wn|C),我们假设这些特征是线性无关的,即都是独立的。则可得:P(W|C)=P(w1|C)P(w2|C)P(w3|C)……P(wn|C)。即我们需要求解在某类条件下某一个特征的概率,这个时候已经转变为我们熟悉的监督分类。我找了两种土地利用类型,一种是城市用地一种是森林用地

基于朴素贝叶斯的图像分类_第1张图片

特征的组织方式为,提取每个图像的RGB三个通道,把三个通道的灰度值连接起来生成特征向量。数据集由50个森林用地图像与50个城市用地组成,按照80% 与 20% 的比例划分训练集与测试集。朴素贝叶斯模型由三种:伯努利模型、多项式模型、混合模型三种。在实验过程中,发现对于图像数据使用多项式模型效果远远不如伯努利模型,笔者猜测可能是由于如果考虑重复值,在图像中往往存在大量的的冗余值如果不考虑重复值的也就是使用伯努利模型时效果最好能达到70%,多项式模型最好达到60%。利用训练集创建好词袋模型后,即可得到每个特征在对应条件下的概率,即建立好模型。将测试集图像样本转换为向量模型后导入创建好的模型,得到P(‘城市用地’|W)与P(‘森林用地’|W) 对比两个概率大小则得到预测结果。在数据集数量小的情况下能达到这种效果,真的很棒了,但是基于朴素贝叶斯对图像进行分类往往就很难用尝试去理解其中的原因,因为它的特征我们假设都是线性无关的,对于图像来说这往往不科学,相邻两个像素值往往关系更大,不仅仅如此对于P(W|C)=P(w1|C)P(w2|C)P(w3|C)……P(wn|C)满足乘法交换法则,也就是说像素的随机组合导致图像可能变的很糟糕,但是他们的效果确是相同的,因此笔者认为如果通过主成分分析等降纬手段提取图像的关键特征可能会达到更好的效果,有兴趣的可以尝试一下。当然目前图像识别中属CNN效果最佳,不过可能需要大量的样本,对于朴素贝叶斯能够在少量样本下达到一个中等的效果还是很令人吃惊的。

如果想要数据提前尝试的话可以联系我,以后也会放到github中,源码如下:

# -*- coding: utf-8 -*-
"""
Created on Mon Feb 26 14:58:03 2018

@author: zhupc
"""
import numpy as np
import h5py 

def loadDataSet():
    '''
    加载图片数据集
    '''
    pictureSet=[];pictureClasses=[]
    with h5py.File('bdata/Land.h5') as h5f:
        forest=h5f['forest'][:]
        urban=h5f['urban'][:]
        pictureSet=np.vstack((forest,urban))
        pictureClasses=[0]*50+[1]*50
    return pictureSet,pictureClasses

def createVocabList(pictureSet):
    '''
    创建一个词袋集合
    '''
    vocabSet=set([])
    for picture in pictureSet:
        vocabSet=vocabSet|set(picture)
    return list(vocabSet)


def randomSpillPictureSet(pictureSet):
    '''
    随机划分训练集与测试集
    '''
    trainingSet=[x for x in range(100)];testSet=[];
    for i in range(20):
        randIndex=int(np.random.uniform(0,len(trainingSet)))   
        testSet.append(trainingSet[randIndex])
        trainingSet.remove(trainingSet[randIndex])
    return trainingSet,testSet
def setOfPix2Vec(vocaList,inputSet):
    '''
    把像素转化为向量
    '''
    returnVec=[0]*len(vocaList)
    for pix in  inputSet:
        if pix in vocaList:
            returnVec[vocaList.index(pix)]=1
    return returnVec

def NBFit(trainMatrix,trainCategory):
    numTrainPictures=len(trainMatrix)
    numPix=len(trainMatrix[0])
    pUrban=sum(trainCategory)/float(numTrainPictures)#城市概率 p(城市)
    #拉普拉斯平滑
    pForestNum=np.ones(numPix);pUrbanNum=np.ones(numPix)
    pFDenom=2;pUDenom=2
    for i in range(numTrainPictures):
        if trainCategory[i]==0:
            pForestNum+=trainMatrix[i]
            pFDenom+=sum(trainMatrix[i])
        else:
            pUrbanNum+=trainMatrix[i]
            pUDenom+=sum(trainMatrix[i])
    pFVect=np.log(pForestNum/pFDenom)
    pUVect=np.log(pUrbanNum/pFDenom)
    return pFVect,pUVect,pUrban

def classifyNB(vecPicture,pFVec,pUVec,pUrban):
    '''
    利用朴素贝叶斯进行分类
    '''
    pF=sum(vecPicture*pFVec)+np.log(1-pUrban)
    pU=sum(vecPicture*pUVec)+np.log(pUrban)
    return 1 if pU/pF>1  else 0

def testingNB():
     pictureSet,pictureClasses=loadDataSet()
     vocabList=createVocabList(pictureSet)
     trainMat=[];trainClasses=[]
     trainingSet,testSet=randomSpillPictureSet(pictureSet)
     for i in trainingSet:
         trainMat.append(setOfPix2Vec(vocabList,pictureSet[i]))
         trainClasses.append(pictureClasses[i])
     pFVect,pUVect,pUrban=NBFit(trainMat,trainClasses)
     errorCount=0
     for i in testSet:
        picVector=setOfPix2Vec(vocabList,pictureSet[i])
        if classifyNB(np.array(picVector),pFVect,pUVect,pUrban)!=pictureClasses[i]:
            errorCount+=1
            print('classification error')
        else:print('分类正确')
     print('the error rate is :',float(errorCount)/len(testSet))
testingNB()

你可能感兴趣的:(机器学习)