『原創』機器學習算法的R語言實現(三):朴素貝葉斯分類器


本人原創,轉載請注明來自 http://www.cnblogs.com/digging4/p/3884385.html

1、引子

朴素貝葉斯方法是一種使用先驗概率去計算后驗概率的方法,其中朴素的意思實際上指的是一個假設條件,后面在舉例中說明。本人以為,純粹的數學推導固然有其嚴密性、邏輯性的特點,但對我等非數學專業的人來說,對每一推導步驟的並非能透徹理解,我將從一個例子入手,類似於應用題的方式,解釋朴素貝葉斯分類器,希望能對公式的理解增加形象化的場景。

2、實例

最近“小蘋果”很火,我們就以蘋果來舉例說,假設可以用三個特征來描述一個蘋果,分別為“尺寸”、“重量”和“顏色”;其中“尺寸”的取值為小、大,“重量”的取值為輕、重,“顏色”取值為紅、綠。對這三個特征描述的蘋果中,對蘋果的按味道進行分類,可取的值為good、bad。

朴素貝葉斯分類器就要要解決如下一個問題,已知蘋果味道取good和bad的概率,那么如果給定一個一組蘋果的特征,那么這個蘋果味道取good和bad的概率是多少?這是個典型的逆概率的問題。

尺寸(size) 大 小 大 大 小 小
重量(weight) 輕 重 輕 輕 重 輕
顏色(color) 紅 紅 紅 綠 紅 綠
味道(taste) good good bad bad bad good

以上給出了6個蘋果的特征描述及其口味,那個一個大而重的紅蘋果,能否估計出它的味道是good還是bad?

這里我們先解釋下朴素的含義,朴素就是這樣一個假設:描述蘋果的三個特征是相互獨立的。這個假設會對后面的計算帶來極大的方便。但是肯定有人會想,對這個例子來說,這個假設就不成立嘛,大小和重量從直覺上我們都會感到是兩個正相關的特征。是的,朴素的假設在實際世界中是較難滿足的,但是實際使用中,基於這個假設作出預測的正確率是在一個可接受的范圍。

3、基本方法

(P(A|B)) 表示在確定B的情況下,事件A發生的概率,而在實際情況中,我們或許更關心(P(B|A))但是只能直接獲得(P(A|B)) ,此時我們需要一個工具可以把(P(A|B)) 和(P(B|A))相互轉化, 貝葉斯定理就是這樣一個公式,下面給出貝葉斯定理:
[P(B|A) = \frac{{P(A|B)P(B)}}{{P(A)}}]

對蘋果分類的問題,有三個特征(F = { {f_1},{f_2},{f_3}} ),兩種分類(C = { {c_1},{c_2}} ),根據貝葉斯公式有給定特征條件下,特征為({c_i})的概率
[P({c_i}|{f_1}{f_2}{f_3}) = \frac{{P({f_1}{f_2}{f_3}|{c_i})P({c_i})}}{{P({f_1}{f_2}{f_3})}}]
使得上式取得最大值的({c_i})即為分類結果,由於對給定訓練集來說,({P({f_1}{f_2}{f_3})})為常數,那么就轉為為求
[{P({f_1}{f_2}{f_3}|{c_i})P({c_i})}]
的最大值。
朴素貝葉斯的假設在這里就體現了,由於特征值相互獨立,那么上式可以轉化為
[P({f_1}|{c_i})P({f_2}|{c_i})P({f_3}|{c_i})P({c_i})]
整個問題就變為求使得上式取最大值的({c_i}),而上式中的每一項都可以從訓練集中得到。

最后討論下Laplace校准,如果某一個特性值在訓練集中出現的次數為0,那么以上我們討論的公式就沒有意義了,以為對所有的類型結果都是0。當然對訓練集進行選擇可以避免這種情況,但是如果避免不了就需要進行Laplace校准。其實很簡單,把所有出現特征出現的次數都加上1,即為Laplace校准。

4、R語言實現

################################
# 朴素貝葉斯分類器
################################

library(plyr)
library(reshape2)

#1、根據訓練集創建朴素貝葉斯分類器
#1.1、生成類別的概率

##計算訓練集合D中類別出現的概率,即P{c_i}
##輸入:trainData 訓練集,類型為數據框
##      strClassName 指明訓練集中名稱為strClassName列為分類結果
##輸出:數據框,P{c_i}的集合,類別名稱|概率(列名為 prob)
class_prob <- function(trainData, strClassName){
  #訓練集樣本數
  length.train <- nrow(trainData)
  dTemp <- ddply(trainData, strClassName, "nrow")
  dTemp <- ddply(dTemp, strClassName, mutate, prob = nrow/length.train)
  dTemp[,-2]
}

##1.2、生成每個類別下,特征取不同值的概率
##計算訓練集合D中,生成每個類別下,特征取不同值的概率,即P{fi|c_i}
##輸入:trainData 訓練集,類型為數據框
##      strClassName 指明訓練集中名稱為strClassName列為分類結果,其余的全部列認為是特征值
##輸出:數據框,P{fi|c_i}的集合,類別名稱|特征名稱|特征取值|概率(列名為 prob)
feature_class_prob <- function(trainData, strClassName){
  # 橫表轉換為縱表
  data.melt <- melt(trainData,id=c(strClassName))
  # 統計頻數
  aa <- ddply(data.melt, c(strClassName,"variable","value"), "nrow")
  # 計算概率
  bb <- ddply(aa, c(strClassName,"variable"), mutate, sum = sum(nrow), prob = nrow/sum)
  # 增加列名
  colnames(bb) <- c("class.name",
                    "feature.name",
                    "feature.value",
                    "feature.nrow",
                    "feature.sum",
                    "prob")
  # 返回結果
  bb[,c(1,2,3,6)]
}

#feature_class_prob(iris,"Species")


## 以上創建完朴素貝葉斯分類器

## 2、使用生成的朴素貝葉斯分類器進行預測
##使用生成的朴素貝葉斯分類器進行預測P{fi|c_i}
##輸入:oneObs 數據框,待預測的樣本,格式為 特征名稱|特征值
##      pc 數據框,訓練集合D中類別出現的概率,即P{c_i}  類別名稱|概率
##      pfc 數據框,每個類別下,特征取不同值的概率,即P{fi|c_i}
##                  類別名稱|特征名稱|特征值|概率
##輸出:數據框,待預測樣本的分類對每個類別的概率,類別名稱|后驗概率(列名為 prob)
pre_class <- function(oneObs, pc,pfc){
  colnames(oneObs) <- c("feature.name", "feature.value")
  colnames(pc) <- c("class.name","prob")
  colnames(pfc) <- c("class.name","feature.name","feature.value","prob")
  
  # 取出特征的取值的條件概率
  feature.all <- join(oneObs,pfc,by=c("feature.name","feature.value"),type="inner")
  # 取出特征取值的條件概率連乘
  feature.prob <- ddply(feature.all,.(class.name),summarize,prob_fea=prod(prob))  #prod為連乘函數
  
  #取出類別的概率
  class.all <- join(feature.prob,pc,by="class.name",type="inner")
  #輸出結果
  ddply(class.all,.(class.name),mutate,pre_prob=prob_fea*prob)[,c(1,4)]
}


##3、數據測試
##用上面蘋果的數據作為例子進行測試
#訓練集
train.apple <-data.frame(
  size=c("大","小","大","大","小","小"),
  weight=c("輕","重","輕","輕","重","輕"),
  color=c("紅","紅","紅","綠","紅","綠"),
  taste=c("good","good","bad","bad","bad","good")
  )
#待預測樣本
oneObs<-data.frame(
  feature.name =c("size", "weight", "color"),
  feature.value =c("大","重","紅")
)

#預測分類
pc <- class_prob(train.apple,"taste")
pfc <- feature_class_prob(train.apple,"taste")
pre_class(oneObs, pc,pfc)

結果為
class.name pre_prob
1 bad 0.07407407
2 good 0.03703704
可見該蘋果的口味為bad

5、朴素貝葉斯分類小結

1、屬於有監督的學習(有訓練集);
2、主要處理離散類型的數據,如果為連續數據可先進行離散化;
3、訓練集的特征取值要盡量完備,如果有缺失需進行預處理(Laplace校准);
4、關於特征值相互獨立的假設,在實際問題中一般無法滿足,但基於此假設做的預測是可以接受的。

關於其他的朴素貝葉斯介紹可見:
http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html
http://www.cnblogs.com/leoo2sk/archive/2010/09/17/1829190.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM