【機器學習與R語言】3-概率學習朴素貝葉斯(NB)


1.理解朴素貝葉斯

1)基本概念

  • 依據概率原則進行分類。如天氣預測概率。
  • 朴素貝葉斯(Naive Bayes, NB)適合場景:為估計一個結果的概率,從眾多屬性中提取的信息應該被同時考慮。
  • 很多算法忽略了弱影響的特征(若有大量弱影響的特征,它們組合在一起的影響可能會很大),但NB算法利用了所有可以獲得的證據來修正預測。
  • 貝葉斯方法的基本概念:事件,試驗,概率,聯合概率,獨立事件,相關事件(建立預測模型的基礎),條件概率,先驗概率,似然概率,邊際似然概率,后驗概率,頻率表
  • 條件概率公式(事件B已經發生的條件下,事件A發生的概率):
    image.png
  • 后驗概率(如商業垃圾郵件過濾器:判斷viagra是垃圾郵件spam的概率):
    image.png

2)朴素貝葉斯算法

  • NB優點:簡單快速有效;能處理噪音及缺失值數據;訓練集不限大小;容易獲得估計概率值。
  • NB缺點:依賴同樣重要和獨立的特征(錯誤假設);應用在大量數值特征的數據集中不理想;概率估計值比預測的類更不可靠。
  • “朴素”的含義:基於這樣一個假設:數據集的所有特征都具有相同的重要性和獨立性,但在大多數實際應用中,假設不成立。
  • 朴素貝葉斯算法具通用性和准確性,在分類學習任務中很強大。

①朴素貝葉斯分類
假設有4個單詞的100封郵件的似然表來訓練朴素貝葉斯算法(如下表),收到新郵件時(包含了單詞viagra和unsubscribe,但不包含money和groceries),通過計算后驗概率來判斷它是否為垃圾郵件。
image.png
原始的基於貝葉斯定理的后驗概率:
image.png
將4個單詞事件視為獨立事件(類條件獨立),可簡化公式:
image.png
計算垃圾郵件總似然為:image.png
計算非垃圾郵件總似然為:image.png
是垃圾郵件的概率為:image.png

②拉普拉斯估計
對於類中一個或多個水平,如果一個時間從沒有發生過,那它出現的概率為0,從而導致后驗概率值也為0(抵消或否決了所有其他的證據)。

比如,這次的新郵件中包含了前述的4個單詞,則計算垃圾郵件的似然:image.png
該郵件是垃圾郵件的概率為:image.png

拉普拉斯估計就是給頻率表中每個計數加上一個很小的數(一般設為1),保證每一類中每個特征發生的概率是非零的。
拉普拉斯估計后的垃圾郵件似然:image.png

③數值型特征值離散化
前面的頻率表要求特征必須為分類變量,如果是數值變量,需要將數值離散化(分段),如根據時間尋找分割點。如果沒有明顯的分割點,也可利用分位數進行分段。

但將數值特征離散化總是會導致信息量的減少,因為特征的原始粒度減少為幾個數目較少的類別。分段太少會導致重要趨勢被掩蓋,分段太多會導致頻率表中的計數值很小,因此需要平衡分段數。

2.朴素貝斯分類應用

示例:基於貝葉斯算法的手機垃圾短信過濾。

1)收集數據

數據下載sms_spam.csv

鏈接: https://pan.baidu.com/s/1fAufKXCSufwd8It_DHXyWQ 提取碼: vgyj

2)探索和准備數據

## Example: Filtering spam SMS messages ----
## Step 2: Exploring and preparing the data ---- 

# read the sms data into the sms data frame
sms_raw <- read.csv("sms_spam.csv", stringsAsFactors = FALSE)

# examine the structure of the sms data
str(sms_raw)

# convert spam/ham to factor.
sms_raw$type <- factor(sms_raw$type)

# examine the type variable more carefully
str(sms_raw$type)
table(sms_raw$type)

處理和分析文本數據

文本挖掘包tm創建語料庫(文本集合),inspect函數查看語料庫內容,tm_map函數轉換tm語料庫(如去數字,變小寫等),stopwords函數去除填充詞(如to/and/or/but等)。

清理完后標記分解單詞形成的組,並創建稀疏矩陣。再進行訓練集和測試集划分,並利用詞雲進行可視化文本數據。最后為高頻詞創建指示特征。

PS:運行過程中tm包的tolower參數一直報錯,未解決,因此本示例最終沒有用此參數。


# build a corpus using the text mining (tm) package
library(tm)
sms_corpus <- VCorpus(VectorSource(sms_raw$text))

# examine the sms corpus
print(sms_corpus)
inspect(sms_corpus[1:2])

as.character(sms_corpus[[1]])
lapply(sms_corpus[1:2], as.character)

# clean up the corpus using tm_map()
# sms_corpus_clean <- tm_map(sms_corpus, content_transformer(tolower)) #Error
sms_corpus_clean <- sms_corpus

# show the difference between sms_corpus and corpus_clean
as.character(sms_corpus[[1]])
as.character(sms_corpus_clean[[1]])

sms_corpus_clean <- tm_map(sms_corpus_clean, removeNumbers) # remove numbers
sms_corpus_clean <- tm_map(sms_corpus_clean, removeWords, stopwords()) # remove stop words
sms_corpus_clean <- tm_map(sms_corpus_clean, removePunctuation) # remove punctuation

# tip: create a custom function to replace (rather than remove) punctuation
removePunctuation("hello...world")
replacePunctuation <- function(x) { gsub("[[:punct:]]+", " ", x) }
replacePunctuation("hello...world")

# illustration of word stemming
library(SnowballC)
wordStem(c("learn", "learned", "learning", "learns"))

sms_corpus_clean <- tm_map(sms_corpus_clean, stemDocument)

sms_corpus_clean <- tm_map(sms_corpus_clean, stripWhitespace) # eliminate unneeded whitespace

# examine the final clean corpus
lapply(sms_corpus[1:3], as.character)
lapply(sms_corpus_clean[1:3], as.character)

# create a document-term sparse matrix
sms_dtm <- DocumentTermMatrix(sms_corpus_clean)

# alternative solution: create a document-term sparse matrix directly from the SMS corpus
sms_dtm2 <- DocumentTermMatrix(sms_corpus, control = list(
  # tolower = TRUE,  #注釋掉也報錯
  removeNumbers = TRUE,
  stopwords = TRUE,
  removePunctuation = TRUE,
  stemming = TRUE
))

# alternative solution: using custom stop words function ensures identical result
sms_dtm3 <- DocumentTermMatrix(sms_corpus, control = list(
  # tolower = TRUE, #注釋掉也報錯
  removeNumbers = TRUE,
  stopwords = function(x) { removeWords(x, stopwords()) },
  removePunctuation = TRUE,
  stemming = TRUE
))

# compare the result
sms_dtm
sms_dtm2
sms_dtm3

# creating training and test datasets
sms_dtm_train <- sms_dtm[1:4169, ]
sms_dtm_test  <- sms_dtm[4170:5558, ]

# also save the labels
sms_train_labels <- sms_raw[1:4169, ]$type
sms_test_labels  <- sms_raw[4170:5558, ]$type

# check that the proportion of spam is similar
prop.table(table(sms_train_labels))
prop.table(table(sms_test_labels))

# word cloud visualization
library(wordcloud)
wordcloud(sms_corpus_clean, min.freq = 50, random.order = FALSE)

# subset the training data into spam and ham groups
spam <- subset(sms_raw, type == "spam")
ham  <- subset(sms_raw, type == "ham")

wordcloud(spam$text, max.words = 40, scale = c(3, 0.5))
wordcloud(ham$text, max.words = 40, scale = c(3, 0.5))

sms_dtm_freq_train <- removeSparseTerms(sms_dtm_train, 0.999)
sms_dtm_freq_train

# indicator features for frequent words
findFreqTerms(sms_dtm_train, 5)

# save frequently-appearing terms to a character vector
sms_freq_words <- findFreqTerms(sms_dtm_train, 5)
str(sms_freq_words)

# create DTMs with only the frequent terms
sms_dtm_freq_train <- sms_dtm_train[ , sms_freq_words]
sms_dtm_freq_test <- sms_dtm_test[ , sms_freq_words]

# convert counts to a factor
convert_counts <- function(x) {
  x <- ifelse(x > 0, "Yes", "No")
}

# apply() convert_counts() to columns of train/test data
sms_train <- apply(sms_dtm_freq_train, MARGIN = 2, convert_counts)
sms_test  <- apply(sms_dtm_freq_test, MARGIN = 2, convert_counts)

得到的sms_trainsms_test的單詞稀疏矩陣如下表所示:
image.png

3)訓練模型

上例已經將原始短信轉換為可以用一個統計模型代表的形式,因此用NB算法根據單詞的存在與否來估計一條給定的短信是垃圾短信的概率。

使用e1071::naiveBays()klaR::NaiveBayes()函數。

## Step 3: Training a model on the data ----
library(e1071)
sms_classifier <- naiveBayes(sms_train, sms_train_labels)

4)評估模型性能

基於測試集中的未知短信來檢驗分類器的預測值。比較預測值和真實值,仍然通過混淆矩陣來計算。

## Step 4: Evaluating model performance ----
sms_test_pred <- predict(sms_classifier, sms_test)

library(gmodels)
CrossTable(sms_test_pred, sms_test_labels,
           prop.chisq = FALSE, prop.t = FALSE, prop.r = FALSE,
           dnn = c('predicted', 'actual'))

image.png

沒怎么處理效果也比較好,所以NB是文本分類的一種標准算法。同樣地,假陰性問題帶來的代價較大(把正常短信過濾掉了),進一步提升模型性能試試。

5)提升模型性能

上面訓練時,沒有設置拉普拉斯估計,此處設為1,性能有所提升。

## Step 5: Improving model performance ----
sms_classifier2 <- naiveBayes(sms_train, 
                          sms_train_labels, 
                          laplace = 1) #拉普拉斯估計值

sms_test_pred2 <- predict(sms_classifier2, sms_test)
CrossTable(sms_test_pred2, sms_test_labels,
           prop.chisq = FALSE, prop.t = FALSE, prop.r = FALSE,
           dnn = c('predicted', 'actual'))

image.png


機器學習與R語言系列推文匯總:
【機器學習與R語言】1-機器學習簡介
【機器學習與R語言】2-K近鄰(kNN)
【機器學習與R語言】3-朴素貝葉斯(NB)
【機器學習與R語言】4-決策樹
【機器學習與R語言】5-規則學習
【機器學習與R語言】6-線性回歸
【機器學習與R語言】7-回歸樹和模型樹
【機器學習與R語言】8-神經網絡
【機器學習與R語言】9-支持向量機
【機器學習與R語言】10-關聯規則
【機器學習與R語言】11-Kmeans聚類
【機器學習與R語言】12-如何評估模型的性能?
【機器學習與R語言】13-如何提高模型的性能?


免責聲明!

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



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