前文介绍了朴素贝叶斯的简单原理及实现,本文则介绍了其在邮件分类中的简单应用。
原理:将邮件正文分词去处停义词后,统计词在在正常及非正常情况下的频数。最终根据贝叶斯定理推断出在指定词下分为正常和非正常的概率,如果P(T)>P(F)且P(T)小于0.8(该阀值可以自己设定),则在判别为正常邮件的同时,需要将该正文写入到正常训练表。同理,如果P(T)<P(F)且P(F)小于0.9(该阀值可以自己设定),也需要将该正文写入到错误训练表。当训练表新增了n份记录时,需要重新训练模型,训练表只保存m份最新记录。通过该方法,则能保证贝叶斯分类器在随着变化而不断更新,处于自我的不断学习。
源码:分为2个,Mail_Bayes_1.R:贝叶斯分类器的生成。
Mail_Bayes_2.R:贝叶斯分类器的实际调用。
Mail_Bayes_1.R
#邮件识别 利用分词 和贝叶斯的方法
setwd("/home/r/work/mail")
library(rJava)
library(Rwordseg)
#增加停用词
stop_word
readLines("../stop_word.dat")
insertWords(stop_word)
library(RMySQL)
library(plyr)
conn
"test",
username="××××",
password="",
host="127.0.0.1",
port=3306)
dbSendQuery(conn,'SET NAMES utf8')
corpus_data
flg, text from bad_mail")
# 分词去处停用词
segmentCN1
temp
segmentCN(string)
temp[! temp %in% stop_word]
}
#计算邮件在不同类型下的频数
BayesTrainMail
function(corpus_data){
temp
table(corpus_data$flg)
temp
as.data.frame(temp)
names(temp)
"freq")
temp$ratio
temp$freq/sum(temp$freq)
temp
}
#计算各个词在不同类型下的频数
BayesTrainWord
function(corpus_data){
flg
unique(corpus_data$flg)
temp
function(x){ unlist(sapply(subset(corpus_data, flg==x)$text,
segmentCN1))})
flg
unlist(sapply(names(temp), function(x){ rep(x,
length(temp[[x]]))}))
word
unlist(sapply(names(temp), function(x){ temp[[x]]}))
names(flg)
NULL
names(word)
NULL
train_data
data.frame(flg, word, stringsAsFactors = F)
train_data
ddply(train_data, .(flg, word), summarize,
freq=length(word))
train_data
}
train_data_mail
BayesTrainMail(corpus_data)
train_data_word
BayesTrainWord(corpus_data)
BayesClassify
function(test_data){
test_word
unique(unlist(segmentCN1(test_data)))
#计算每个词的条件概率 默认都加1 防止未出现
freq
unlist(sapply(train_data_mail$flg, function(y){
sapply(test_word,
function(x){ifelse(length(subset(train_data_word,
word==x&flg==y)$freq)==0,
1, subset(train_data_word,
word==x&flg==y)$freq+1)})}))
colnames(freq)
train_data_mail$flg
p_prob1
sapply(colnames(freq), function(x){ prod(freq[,
x])/(sum(subset(train_data_word, flg==x)$freq)+
sum(train_data_word$freq))})
# 连乘条件概率后再乘以总的类别概率
p_prob
sapply(names(p_prob1),
function(x){p_prob1[x]*subset(train_data_mail,
flg==x)$ratio})
names(p_prob)
p_prob
p_prob/(sum(p_prob))
p_prob
}
Mail_Bayes_2.R
setwd("/home/r/work/mail")
library(rJava)
library(Rwordseg)
#增加停用词
stop_word
readLines("../stop_word.dat")
insertWords(stop_word)
library(RMySQL)
library(plyr)
conn
"test",
username="×××",
password="",
host="127.0.0.1",
port=3306)
dbSendQuery(conn,'SET NAMES utf8')
source("./Mail_Bayes_1.R")
#邮件分类默认存放位置
write.table(data.frame("mail", "flg",
"time"),
file="./mail_result.dat", sep="---", row.names=F,
col.names=F)
#默认计数 如果基础词义库新增记录达到50条 重新训练模型
num
# 实际应用中 初始的词义库是不够全的
需要模型的继续学习 基础词义库只保留100条记录,按插入时间先后来删除历史
# 对于P(N) >
P(Y)但是P(N)<0.8的mail 将其扔入基础词义库训练
# 对于P(N) <
P(Y)但是P(Y)<0.9的mail 将其扔入基础词义库训练
Classify
prob
BayesClassify(test_data$word)
if(prob["N"]>prob["Y"]){
write.table(data.frame(mail=test_data$num, flg="正常邮件",
time=as.character(Sys.time())),
file="./mail_result.dat",
sep="---", row.names=F, append=T, col.names=F)
if(prob["N"]<0.8){
cnt
bad_mail where flg='N'")
if(cnt$cnt==100){
dbSendQuery(conn, "delete from
bad_mail where flg='N' and insert_time in ( select min(insert_time)
from bad_mail where flg='N')")
dbCommit(conn)
}
dbSendQuery(conn, paste(paste("insert into bad_mail values('N ",
gsub("'", "", test_data$word),
as.character(Sys.time()),
sep="','"), "')", sep=""))
dbCommit(conn)
num <
}
}else{
write.table(data.frame(mail=test_data$num, flg="垃圾邮件",
time=as.character(Sys.time())),
file="./mail_result.dat",
sep="---", row.names=F, append=T, col.names=F)
if(prob["Y"]<0.9){
cnt
bad_mail where flg='Y'")
if(cnt$cnt==100){
dbSendQuery(conn, "delete from
bad_mail where flg='Y' and insert_time in ( select min(insert_time)
from bad_mail where flg='Y')")
dbCommit(conn)
}
dbSendQuery(conn, paste(paste("insert into bad_mail values('Y ",
gsub("'", "", test_data$word),
as.character(Sys.time()),
sep="','"), "')", sep=""))
dbCommit(conn)
num <
}
}
#新增记录大于预设值
重新训练模型
if(num>=50){
write.table(data.frame(mail="开始训练模型", flg="训练模型",
time=as.character(Sys.time())),
file="./mail_result.dat",
sep="---", row.names=F, append=T, col.names=F)
corpus_data
bad_mail")
train_data_mail
<
BayesTrainMail(corpus_data)
train_data_word
<
num
<
write.table(data.frame(mail="结束训练模型", flg="训练模型",
time=as.character(Sys.time())),
file="./mail_result.dat",
sep="---", row.names=F, append=T, col.names=F)
}
}
总结:此处只是朴素贝叶斯分类器在分类中的简单实现,实际应用中需要添加和业务相关的限制。