R语言:朴素贝叶斯算法实现对中文垃圾邮件的分类


本期主要是实操在R语言中如何使用朴素贝叶斯算法实现对中文垃圾邮件的分类,并尝试优化模型分类效果。本文中所用到的数据均为真实的中文邮件文本数据,因此整个过程十分贴近真实的操作场景,能够帮助我们更深入的理解和掌握在R语言中如何进行中文文本处理和如何使用朴素贝叶斯算法进行分类。关于算法原理本文将不作介绍,需要了解的同学可以百度一下,网上有许多非常深入和详细解读。

数据基本情况

在开始进行文本分类之前我们需要了解一下数据的基本情况以便我们理清数据处理的思路,这是非常重要的一步,对数据结构有了清晰的认识才能够事半功倍。数据获取:https://trec.nist.gov/data/spam.html,下载2006垃圾邮件语料库,其中的trec06c文件为本文中使用的数据

首先,我们导入一份邮件,来看看这份数据文件内的中文邮件长什么样子。

setwd("~/Desktop/R/python/email/trec06c") 
email_exm <- read.table("data/001/005",fill=TRUE,fileEncoding = "GB18030",sep = "|")

该文件内包含了一份邮件所应该的全部信息,然而我们实际需要的只是其中邮件的正文部分,其他的信息都是基本用不到,是要被清理掉的,这其中主要是一些英文字符、特殊符号以及数字。另外,为了方便后续对中文文本进行分词的处理,我们需要将读入多行的数据合并成一行。

粗略阅读该邮件的内容,发现这是一份翻译公司的推销邮件, 显然这是一份垃圾邮件。full文件夹中的index文件中标记了邮件是否为垃圾邮件,我们将index文件导入,查看一下这份数据的结构。

library(dplyr)
email_class_full <- read.table("full/index",fill=TRUE,fileEncoding = "GB18030",col.names = c("type","path"))
str(email_class_full)
prop.table(table(email_class_full$type))
head(email_class_full)
filter(email_class_full,path == "../data/001/005")

index文件包含了所有邮件的文件路径以及邮件的是否为垃圾邮件,一共64620行数据,即64620份邮件,其中非垃圾邮件占比为33.68%,垃圾邮件占比66.32%;另外我们查看了data/001/005的类型,为spam,其的确为垃圾邮件。后续的数据处理中我们将随机抽取其中的10000份邮件,通过index中的文件路径将抽样的文本导入。

文本数据导入

library(dplyr)
library(plyr)
library(stringr)
#随机抽取10000条数据
email_class_full <- email_class_full[sample(1:length(email_class_full$type),size=10000),]
#准备for循环中用到的变量
warn_path = c()
emails = c()
num <- length(email_class_full$type)

#逐一读入文件
for(i in 1:num){
  #截取邮件的文件路径
  path <- str_sub(email_class_full[i,2],4)
  
  #个别邮件包含无法识别的特殊字符无法读入,将其抓取出来
  warn <-tryCatch(
    {text <- read.table(path,fill=TRUE,fileEncoding = "GB18030",colClasses ="character",sep = "|")},
    warning = function(w){"warning"}
  )
  if(warn == "warning"){  warn_path <- c(warn_path,as.character(email_class_full[i,2]))}
  
  #去除文本中的英文字符、特殊字符
  arrange_text <- gsub("[a-zA-Z]","",as.character(warn)) %>% 
    gsub('[\\(\\.\\\\)-<\n-=@\\>?_]',"",.)
  
  #将处理后的文本保存
  emails <- c(emails,arrange_text)
}
normal_emails <- mutate(email_class_full,text = emails,type = factor(type))  %>% filter(.,text !="")
warn_emails <- mutate(email_class_full,text = emails)  %>% filter(.,text =="")

随机抽取10000份邮件导入并进行初步的数据清洗后,我们查看一下导入后的数据情况。基本上文本内容均是我们所需要的汉字正文,可以进行下一步的分词提取关键词了。

文本分词处理

在用朴素贝叶斯算法进行邮件分类之前,需对整段的中文文本进行分词,并提取关键词。本文中用的中文分词包为jiebaR,分词后的数据格式整理用的是tm包,如果是处理英文文本,则可直接使用tm包,其十分强大,能够很方便的处理英文文本,但是对中文文本的支持则没有那么完善。

#分词并提取关键词
engine <- worker()
keys = worker("keywords",topn=20)
clean_word <- function(data){
  return(paste(unique(vector_keywords(segment(data$text,engine),keys)),collapse=" "))
}
email_words <- ddply(normal_emails,.(type,path),clean_word) %>% rename(.,replace = c("V1" = "words"))

#建立语料库
emails_corpus <- Corpus(VectorSource(email_words$words)) %>% tm_map(.,stripWhitespace)
#创建文档-单词矩阵
emails_dtm <-  DocumentTermMatrix(emails_corpus)

垃圾邮件分类

在文本数据处理完后,则可以开始进行垃圾邮件分类了!本文中进行垃圾邮件分类用的是e1071包。

library(dplyr)
library(plyr)
library(stringr)
library(tm)
library(jiebaR)
library(e1071)
#随机抽取70%的数据作为训练集,剩下的30%作为测试集
train_row <- sample(1:length(email_words$type),size = floor((length(email_words$type) *0.7)))
email_words_train <- email_words[train_row,]
email_words_test <-  email_words[-train_row,]

emails_dtm_train <- emails_dtm[train_row,]
emails_dtm_test <- emails_dtm[-train_row,]

emails_corpus_train <- emails_corpus[train_row]
emails_corpus_test <- emails_corpus[-train_row]

#选取词频>=5的词汇
emails_words_dict <- findFreqTerms(emails_dtm_train,5)
emails_corpus_freq_train <- DocumentTermMatrix(emails_corpus_train,list(dictionry = emails_words_dict))
emails_corpus_freq_test <- DocumentTermMatrix(emails_corpus_test,list(dictionry = emails_words_dict))
#将训练集和测试集中的词用0,1分别标记在文本中未出现、出现某一词汇
convert_counts <- function(x){
  x <- ifelse(as.numeric(as.character(x))>0,1,0)
  x <- factor(x,levels = c(0,1),labels = c("No","Yes"))
  return(x)
}
emails_corpus_convert_train <- apply(emails_corpus_freq_train,MARGIN = 2,convert_counts)
emails_corpus_convert_test <- apply(emails_corpus_freq_test,MARGIN = 2,convert_counts)
#利用朴素贝叶斯算法进行分类
emails_naiveBayes <- naiveBayes(emails_corpus_convert_train,email_words_train$type,laplace = 1)
#测试分类的效果
emails_predict  <- predict(emails_naiveBayes,emails_corpus_convert_test)

我们来看一下分类器对测试集的分类效果,

library(gmodels)
CrossTable(emails_predict,email_words_test$type)

926条非垃圾邮件数据中的14条被误分为垃圾邮件,占比1.5%;1464条垃圾邮件数据中的1295条被正确分类,占比88.5%。详细情况如下:

分类过程中的尝试

在得到最终的分类结果之前,还进行了一些尝试,得到分类器效果均不及最终的分类结果,具体情况如下:
1.在分词后,关键词选取文本中出现的名词、形容词作为输入模型的数据,得到的分类器将926条非垃圾邮件数据中的30条误分为垃圾邮件,占比3.2%;1464条垃圾邮件数据中的1202条被正确分类,占比83.3%。
2.以TF-IDF值筛选关键词,但是训练分类器时未加入拉普拉斯平滑,得到的分类器将926条非垃圾邮件数据中的20条误分为垃圾邮件,占比2.2%;1464条垃圾邮件数据中的1230条被正确分类,占比84%。

以上是在R语言朴素贝叶斯算法进行垃圾邮件分类的全过程。如有做的不好或这不对的地方还请大家指正!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容

  • 后期整理字体以及排版问题,修订不适合的翻译 “A wealth of information. Smart, ye...
    iamzzz阅读 739评论 0 0
  • 2006年,对那时的我来说,一个灰暗的时间,中考失利!在浑浑噩噩度过了三年初中后,考取了当时我以为是最差的高中! ...
    安语乎阅读 217评论 0 0
  • 1.C++函数参数个数不定(http://blog.csdn.net/huangwwu11/article/det...
    zjh3029阅读 189评论 0 0
  • 4月的一个晚上,我正窝在家里,一边给傲娇火辣的小龙虾剥皮,一边给喵主子花花踩背。 身后是末尾阶层的盛先生,一边唱着...
    栗五阅读 212评论 0 1
  • 01 我是家中的独子,家境不错,有房有车,有几间铺面在出租,老婆是乡下人,有一个弟弟,我俩二十多岁的时候认识,朴实...
    喵呜么么阅读 254评论 0 0