朴素贝叶斯分类之垃圾短信识别

在上一篇文章中我们使用最邻近算法knn实现医学中乳腺癌的判别,本文继续探讨分类算法,该算法是朴素贝叶斯分类算法,它有着非常多的优点,具体表现在简单、快速、有效,对噪声数据和缺失数据不敏感,而且还可以得到分类结果的概率值。


算法思想

该算法根据训练数据集的取值计算已知分类的各种概率,在完成学习的过程后,如果将一个未分类的样本带入到算法中,分类器根据样本的特征计算概率并将其判为应该属于的类。


贝叶斯条件概率

上文中提到的概率都是基于贝叶斯条件概率公式计算所得,具体公式如下:

0?wx_fmt=jpeg
该公式表示,已知事件B发生的条件下,事件A发生的概率。举个例子说,已知某人吸烟的情况下,其可能得肺癌的概率就可以根据该公式计算所得。

这里需要注意的是,贝叶斯条件概率计算的是某事件发生的概率,所以对原始数据有一个潜在的假设,即变量值尽可能的离散化(成为独立的事件),如果变量值是大量的连续数据,算法可能得到不理想的分类结果。


应用--垃圾短信识别

接下来将使用该算法实现垃圾短信的识别,垃圾短信的识别又将涉及到文本文字的处理,数据来源于http://www.dt.fee.unicamp.br/~tiago/smsspamcollection/


一、读取数据

sms_rawdata <- read.csv(file = file.choose(), header = TRUE, stringsAsFactors = FALSE)

#查看数据前6行

head(sms_rawdata)

朴素贝叶斯分类之垃圾短信识别_第1张图片
#查看数据概要

str(sms_rawdata)

朴素贝叶斯分类之垃圾短信识别_第2张图片
由于短信的类型是分类变量,这里进一步将其处理为因子

sms_rawdata$type <- factor(sms_rawdata$type)

#查看短信类型的数量

table(sms_rawdata$type)

prop.table(table(sms_rawdata$type))

朴素贝叶斯分类之垃圾短信识别_第3张图片
垃圾短信有747条,占了13.4%的比重。


二、文本处理

在文本分析之前需要使用tm包将文本处理干净,主要是文本信息中含有的一些没有意义的内容,如标点符号、数字、停止词等。

#下载并加载tm包

if(!suppressWarnings(require('tm'))){

install.packages('tm')

require('tm')

}

#首先将文本数据导入为语料库(Corpus函数)

sms_corpus <- Corpus(VectorSource(sms_rawdata$text))

#查看语料库

sms_corpus

朴素贝叶斯分类之垃圾短信识别_第4张图片
发现语料库中包含5558个文件即短信。


使用tm_map函数将没有意义的信息剔除

#所有单词转化为小写

sms_clean <- tm_map(sms_corpus,content_transformer(tolower))

#剔除所有标点符号

sms_clean <- tm_map(sms_clean,removePunctuation)

#剔除所有数字

sms_clean <- tm_map(sms_clean,removeNumbers)

#剔除所有停止词,如a/the等,使用tm包自带的停止词

sms_clean <- tm_map(sms_clean,removeWords,stopwords())

#剔除所有空格

sms_clean <- tm_map(sms_clean,stripWhitespace)


创建符合贝叶斯算法的数据集(文档词条矩阵),矩阵的行表示短信条数,矩阵的列表示单词。

sms_dtm <- DocumentTermMatrix(x = sms_clean)

sms_dtm

朴素贝叶斯分类之垃圾短信识别_第5张图片
该文档词条矩阵包含了8300多列,超过了短信的条数,这将导致算法无法准确分类,为了减少矩阵的列数,我们将剔除同一个单词出现在少于5条短信的单词。这里的5表示总短信条数的0.1%。

#将文档词条矩阵转化为数据框

sms_dtm2 <- as.data.frame(inspect(sms_dtm))

sms_dtm2 <- sms_dtm2[,findFreqTerms(sms_dtm,5)]

dim(sms_dtm2)

[1] 5558 1542

#现在还剩1542列


三、文本探索

在建模之前,我们对文本进行一个初步的探索--词云

#下载并加载wordcloud包

if(!suppressWarnings(require('wordcloud'))){

install.packages('wordcloud')

require('wordcloud')

}

#绘制文字云

par(bg='black')

wordcloud(words = sms_clean, min.freq = 50, scale = c(2.5,0.5),colors=rainbow(10))

朴素贝叶斯分类之垃圾短信识别_第6张图片

四、建模

由于文档词条矩阵中的数值表示某个单词出现在一条短信中的次数,所以需要将连续数值离散化,这里将大于等于1的值用YES表示,否则用NO表示。

#构建离散化的自定义函数

numtochar <- function(x){

ifelse(x >= 1, 'YES', 'NO')

}

#将自定义函数应用到数据框中的每一列

sms_dtm2 <- sapply(sms_dtm2, numtochar)


#创建训练集和测试集

set.seed(1234)

index <- sample(1:2, size = nrow(sms_rawdata), replace = TRUE, prob = c(0.7,0.3))

train_data <- sms_dtm2[index == 1,]

train_Y <- sms_rawdata[index == 1, 1]

test_data <- sms_dtm2[index == 2,]

test_Y <- sms_rawdata[index == 2, 1]


五、函数简介

接下来使用klaR包中的NaiveBayes()函数实现贝叶斯分类算法,NaiveBayes()函数的语法和参数如下:

NaiveBayes(formula, data, ..., subset, na.action = na.pass)

NaiveBayes(x, grouping, prior, usekernel = FALSE, fL = 0, ...)


formula指定参与模型计算的变量,以公式形式给出,类似于y=x1+x2+x3;

data用于指定需要分析的数据对象;

na.action指定缺失值的处理方法,默认情况下不将缺失值纳入模型计算,也不会发生报错信息,当设为“na.omit”时则会删除含有缺失值的样本;

x指定需要处理的数据,可以是数据框形式,也可以是矩阵形式;

grouping为每个观测样本指定所属类别;

prior可为各个类别指定先验概率,默认情况下用各个类别的样本比例作为先验概率;

usekernel指定密度估计的方法(在无法判断数据的分布时,采用密度密度估计方法),默认情况下使用标准的密度估计,设为TRUE时,则使用核密度估计方法;

fL指定是否进行拉普拉斯修正,默认情况下不对数据进行修正,当数据量较小时,可以设置该参数为1,即进行拉普拉斯修正。


#下载并加载klaR包

if(!suppressWarnings(require('klaR'))){

install.packages('klaR')

require('klaR')

}

#使用训练集建模

model <- NaiveBayes(x = train_data, grouping = train_Y, fL = 1)

#使用测试集对模型的准确性进行鉴定

pre <- predict(model, newdata = test_data)

Freq <- table(pre$class, test_Y)

Freq

accuracy <- sum(diag(Freq))/sum(Freq)

accuracy

朴素贝叶斯分类之垃圾短信识别_第7张图片
模型的准确率近98%。


本文不足之处主要是没能够使用中文短信作为案例,如果条件允许,能够搜集到大量的中文短信或邮件,我还是想再走一遍流程。关于中文文本的分析,会多一个分词的步骤,其余基本上和英文文本分析步骤一致。


下载链接

文中的数据和脚本可到如下链接中下载:

http://yunpan.cn/c3EbuNdFzsvN4 访问密码 6c39


总结:文章使用到的R包和函数

read.csv()

table()

prop.table()

sapply()

tm包

Corpus()

tm_map()

DocumentTermMatrix()

inspect()

findFreqTerms()

wordcloud包

wordcloud()

klaR包

NaiveBayes()

predict()

你可能感兴趣的:(朴素贝叶斯分类之垃圾短信识别)