用R进行朴素贝叶斯分类
- 原理介绍
- 应用领域
- 基于贝叶斯定理的条件概率
- 朴素贝叶斯算法
- Example: Filtering spam SMS messages ----
- Step 1: Exploring and preparing the data ----
- read the sms data into the sms data frame
- examine the structure of the sms data
- convert spam/ham to factor.
- examine the type variable more carefully
- build a corpus using the text mining ('tm') package
- examine the sms corpus
- clean up the corpus using tm_map()
- show the difference between sms_corpus and corpus_clean
- 所有短信字母变成小写字母&删除数字
- 删除停用词
- 删除标点符号
- 删除多于空格
- 观察一些变换前后的结果
- create a document-term sparse matrix
- creating training and test datasets
- also save the labels
- check that the proportion of spam is similar
- word cloud visualization
- subset the training data into spam and ham groups
- 剔除训练数据中出现次数少于记录总数0.1%的单词
- indicator features for frequent words
- create DTMs with only the frequent terms
- convert counts to a factor
- apply() convert_counts() to columns of train/test data
- Step 2: Training a model on the data ----
- 分类模型建立
- Step 3: Evaluating model performance ----
- Step 4: Improving model performance ----
原理介绍
应用领域
基于贝叶斯方法的分类器是利用训练数据并根据特征的取值来计算每个类别被观察到的概率。当分类器之后被应用到无标签数据时,分类器就会根据观测到的概率来预测新的特征最有可能属于哪个类。这是简单的想法,但根据这种想法就产生了一种方法,这种方法得到的结果与很多复杂算法得到的结果是等价的。事实上,贝叶斯分类器已用于以下方面:
- 文本分类,比如垃圾邮件过滤、作者识别和主题分类等。
- 在计算机网络中进行入侵检测或者异常检测。
- 根据一组观察到的症状,诊断身体状况。
通常情况下,贝叶斯分类器最适用于解决这样一类问题:在这类问题中,为了估计一个结果的概率,从众多属性中提取的信息应该被同时考虑。尽管很多算法忽略了具有弱影响的一些特征,但是贝叶斯方法利用了所有可以获得的证据来巧妙地修正预测。如果有大量特征产生的影响较小,但将它们放在一起,它们的组合影响可能会相当大。
基于贝叶斯定理的条件概率
相关事件之间的关系可以用贝叶斯定理来描述,如下面的公式所示。符号P(A|B)表示在事件B已经发生的条件下,事件A发生的概率。这就是条件概率,因为事件A发生的概率依赖于事件B的发生(即条件)。
为了理解贝叶斯定理在实际中的应用,可以假设你的任务是估算收到的电子邮件是垃圾邮件的概率。在没有任何附加证据的条件下,最合理的猜测就是事先收到垃圾邮件的概率,即前面例子中的20%,这个估计称为先验概率。
现在,假设你获得了一条额外的证据,你被告知收到的电子邮件使用了单词Viagra,在先前的垃圾邮件中出现单词Viagra的概率称为似然概率(likelihood),而单词Viagra出现在任何一封邮件中的概率称为边际似然概率(marginal likelihood)。
将贝叶斯定理应用到这条额外的证据上,我们可以计算后验概率(posterior),这个概率用来衡量该邮件是垃圾邮件的可能性。如果计算出的后验概率远大于50%,则该信息更可能是垃圾信息,应该过滤掉。下面的公式就是对于给定证据的贝叶斯定理:
朴素贝叶斯算法
朴素贝叶斯(Naive Bayes,NB)算法描述应用贝叶斯定理进行分类的一个简单应用。尽管这不是唯一应用贝叶斯方法的机器学习方法,但它是最常见的,尤其在文本分类应用中已经成为一种准则。该算法的优缺点如下表所示。
朴素贝叶斯算法之所以这样命名是因为关于数据有一对“简单”的假设。特别地,朴素贝叶斯假设数据集的所有特征都具有相同的重要性和独立性,而在大多数的实际应用中,这些假设是鲜有成立的。
举个例子,假设你试图通过监控电子邮件来识别垃圾邮件,那么几乎可以肯定,邮件中的某些特征比其他特征更重要。比如,相对邮件内容来说,电子邮件的发件人是判别垃圾邮件的一个更重要的指标。而且,出现在邮件主体中的词和主体中的其他词并不是相互独立的,因为有些词的出现正好暗示着其他词很可能出现。一封含有单词Viagra的邮件有极大的可能包含单词prescription 或者drug。
然而,在大多数情况下,当违背这些假设时,朴素贝叶斯依然可以很好地应用,甚至在极端事件中,特征之间具有很强的依赖性时,朴素贝叶斯也可以用。由于该算法的通用性和准确性,适用于很多类型的条件,所以在分类学习任务中,朴素贝叶斯算法往往是很强大的,排在候选算法的第一位。
Example: Filtering spam SMS messages ----
Step 1: Exploring and preparing the data ----
read the sms data into the sms data frame
sms_raw <- read.csv("F:\\rwork\\Machine Learning with R (2nd Ed.)\\Chapter 04\\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)
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))#全部小写
show the difference between sms_corpus and corpus_clean
as.character(sms_corpus[[1]])
as.character(sms_corpus_clean[[1]])
所有短信字母变成小写字母&删除数字
corpus_clean <-tm_map(sms_corpus,tolower)
sms_corpus_clean <- tm_map(sms_corpus_clean, removeNumbers)
删除停用词
sms_corpus_clean <- tm_map(sms_corpus_clean, removeWords, stopwords())
stopwords里面是to,and,but等一些自带的一些词
删除标点符号
sms_corpus_clean <- tm_map(sms_corpus_clean, removePunctuation)
删除多于空格
sms_corpus_clean <- tm_map(sms_corpus_clean, stripWhitespace)
观察一些变换前后的结果
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)
这条命令将语料库标记化,并返回一个名为sms_dtm的稀疏矩阵。从这里,我们就可以对包括词频在内的信息进行分析。
creating training and test datasets
一部分作为训练数据,一部分作为测试数据
sms_dtm_train <- sms_dtm[1:4169, ]
sms_dtm_test <- sms_dtm[4170:5559, ]
also save the labels
sms_train_labels <- sms_raw[1:4169, ]$type
sms_test_labels <- sms_raw[4170:5559, ]$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)
在语料库最小次数50次;不随机排列
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))#最常见的40个单词
wordcloud(ham$text, max.words = 40, scale = c(3, 0.5))
剔除训练数据中出现次数少于记录总数0.1%的单词
sms_dtm_freq_train <- removeSparseTerms(sms_dtm_train, 0.999)
indicator features for frequent words
找出最少出现5次的单词
sms_freq_words <- findFreqTerms(sms_dtm_train, 5)
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
如果大于1就是Yes
convert_counts <- function(x) {
x <- ifelse(x > 0, "Yes", "No")}
apply() convert_counts() to columns of train/test data
将语料中不是0的全部换为Yes
sms_train <- apply(sms_dtm_freq_train, MARGIN = 2, convert_counts)
sms_test <- apply(sms_dtm_freq_test, MARGIN = 2, convert_counts)
Step 2: Training a model on the data ----
分类模型建立
library(e1071)
sms_classifier <- naiveBayes(sms_train, sms_train_labels)
Step 3: 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'))
发现有6+34=40条短信未被正确分类
Step 4: 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'))
改善模型,将拉普拉斯(laplace)值设为1,发现有6+32=38条短信未被正确分类。
虽然从40到38看上去是一个很小的变化,考虑到模型的准确性已经相当好了,这其实是很大的提高。
最终该模型将超过97%的短信正确分成垃圾短信和非垃圾短信。