当前位置: 首页 > news >正文

朴素贝叶斯算法代码实现(垃圾邮件检测)

1.文本预处理

(1)分词

首先需要对文本进行分词操作,转换为list,同时词语全部小写,并去除字母数量小于等于2的单词

# 将词切分为list
def textParse(input_string):
    listofTokens = re.split(r'\W+',input_string)
    return [tok.lower() for tok in listofTokens if len(listofTokens)>2]

(2)创建语料表

对于每一封邮件,我们需要得到每一封邮件出现的词语,即语料表

# 创建语料表
def creatVocablist(doclist):
    vocabSet = set([])
    for document in doclist:
        vocabSet = vocabSet|set(document)   # 对语料表中的每个词,取集合的并集
    return list(vocabSet)

 (3)得到词向量

首先初始化一个向量,只要对应词在邮件中出现,相应位置置1,于是我们得到了词向量

# 得到词向量
def setOfWord2Vec(vocablist,inputSet):
    returnVec  = [0]*len(vocablist) # 初始化
    # 只要对应位置的词在语料表中出现了,置为1
    for word in inputSet:
        if word in vocablist:
            returnVec[vocablist.index(word)] = 1
    return returnVec

串联起来:

        首先读取邮件,得到每个邮件的语料表,然后划分训练集和测试集,得到训练集每个邮件的词向量以及类别(垃圾邮件/非垃圾邮件) 

 

 2.训练模块

        首先,我们回顾一下朴素贝叶斯原理和公式:

问题:给定一封邮件,判定它是否属于垃圾邮件D来表示这封邮件,注意 D 由 N 个单词组成。我们用 h+ 来表示 垃圾邮件,h- 表示正常邮件
P(h+|D) = P(h+) * P(D|h+) / P(D)

P(h- |D) = P(h- ) * P(D|h- ) / P(D)

先验概率:P(h+) 和 P(h-) 这两个先验概率都是很容易求出来的,只需要计算一个邮件库里面垃圾邮件和正常邮件的比例就行了。
D 里面含有 N 个单词 d1, d2, d3,P(D|h+) = P(d1,d2,..,dn|h+) P(d1,d2,..,dn|h+) 就是说在垃圾邮件当中出现跟我们目前这封邮件一 模一样的一封邮件的概率是多大!
 

 P(d1,d2,..,dn|h+) 扩展为: P(d1|h+) * P(d2|d1, h+) * P(d3|d2,d1,

h+) * ..
 P(d1|h+) * P(d2|d1, h+) * P(d3|d2,d1, h+) * .. 假设 di 与 di-1 是完全条件无关的(朴素贝叶斯假设特征之间是独 立,互不影响)

简化为 P(d1|h+) * P(d2|h+) * P(d3|h+) * ..
对于P(d1|h+) * P(d2|h+) * P(d3|h+) * ..只要统计 di 这个单词在垃圾邮件中出现的频率即可

同时,对于不同的具体猜测 h1 h2 h3 .. ,P(D) 都是一样的,所以在比较P(h+ | D) 和 P(h2-| D) 的时候我们可以忽略这个常数

因此,我们需要得到P(h+)、P(D|h+)、P(D|h- )

对于P(h+),我们只需要用垃圾邮件数/总邮件数即可。

对于P(D|h+),我们需要得到垃圾邮件词向量/总的词语数量,对于初始化,我们采用拉普拉斯初始化,即分子用1进行初始化,分母用类别数量进行初始化。最后,由于求得的概率值太小,我们取对数,将数值扩大。

对于P(D|h- ),我们也采取同样的操作

# 朴素贝叶斯算法训练模块
def trainNB(trainMat,trainClass):
    numTrainDocs = len(trainMat) # 总的邮件数
    numWords = len(trainMat[0]) # 总的词语数量
    p1 = sum(trainClass)/float(numTrainDocs) # 垃圾邮件的概率
    p0Num = np.ones((numWords)) #做了一个平滑处理
    p1Num = np.ones((numWords)) #拉普拉斯平滑,分子用1初始化,分母用类别个数初始化
    p0Denom = 2
    p1Denom = 2 #通常情况下都是设置成类别个数
    
    for i in range(numTrainDocs):
        if trainClass[i] == 1: #垃圾邮件
            p1Num += trainMat[i] # 垃圾邮件词语数量
            p1Denom += sum(trainMat[i]) # 分母,垃圾邮件总的词语数量
        else:   # 正常邮件
            p0Num += trainMat[i] #
            p0Denom += sum(trainMat[i])
    p1Vec = np.log(p1Num/p1Denom)
    p0Vec = np.log(p0Num/p0Denom)
    return p0Vec,p1Vec,p1

3.推理模块

        首先我们观察公式,P(h+|D) = P(h+) * P(D|h+)(按照上面所说,P(D)为常数,不考虑),即log(h+|D) = log(P(h+) )+log( P(D|h+)),同理log(h-|D) = log(P(h-) )+log( P(D|h-))。如果log(h+|D)>log(h-|D) ,我们即可认为该邮件为垃圾邮件(正类为垃圾邮件)。

代码如下:(用词向量直接乘以邮件中出现对应词的概率即可直接筛选出出现的词语及其概率)

def classifyNB(wordVec,p0Vec,p1Vec,p1_class):    
    p1 = np.log(p1_class) + sum(wordVec*p1Vec) # 对数形式
    p0 = np.log(1.0 - p1_class) + sum(wordVec*p0Vec)
    if p0>p1:
        return 0
    else:
        return 1

总的代码如下:

def spam():
    doclist = []
    classlist = []
    for i in range(1,26):
        # 将词切分为list
        wordlist = textParse(open('email/spam/%d.txt'%i,'r').read())
        doclist.append(wordlist)    # 文件中的所有词
        classlist.append(1) #1表示垃圾邮件
        
        wordlist = textParse(open('email/ham/%d.txt'%i,'r').read())
        doclist.append(wordlist)
        classlist.append(0) #1表示垃圾邮件
    # 创建语料表
    vocablist = creatVocablist(doclist)
    trainSet = list(range(50))  # 训练集
    testSet = []    # 测试集
    # 取出10个数据作为测试集,并删掉取出的数据,余下的数据作为训练集
    for i in range(10):
        randIndex = int(random.uniform(0,len(trainSet)))
        testSet.append(trainSet[randIndex])
        del (trainSet[randIndex])
    trainMat = []   # 词向量
    trainClass = [] # 邮件类别
    # 获取词向量与相应的类别
    for docIndex in trainSet:
        trainMat.append(setOfWord2Vec(vocablist,doclist[docIndex]))
        trainClass.append(classlist[docIndex])
    p0Vec,p1Vec,p1 = trainNB(np.array(trainMat),np.array(trainClass))
    errorCount = 0
    for docIndex in testSet:
        wordVec = setOfWord2Vec(vocablist,doclist[docIndex])
        if classifyNB(np.array(wordVec),p0Vec,p1Vec,p1) != classlist[docIndex]:
            errorCount+=1
    print ('当前10个测试样本,错了:',errorCount) 

 

 

相关文章:

  • U3D对话任务插件 Dialogue System for Unity 研究(一)
  • ArchLinux 的vm-tools无法正常使用的解决办法
  • idea安装scala
  • Vue2.0 双向绑定的缺陷
  • FDA药品分类目录清单查询
  • 总结——0923
  • 北鲲云“药物发现”轻装上阵,从“上云”到“用好云”
  • 微服务项目:尚融宝(55)(核心业务流程:放款(2))
  • 第七:Fiddler抓包教程(7)-Fiddler状态面板-QuickExec命令行
  • C++标准语言day02
  • 1456. 定长子串中元音的最大数目-前缀和算法应用
  • Spartan Labs研报:基础SBT以及隐私性SBT的实现
  • 【英语:基础进阶_语法进阶提升】F7.非谓语动词
  • jenkins教程
  • 《Java并发编程的艺术》——Java并发的前置知识(笔记)
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • django开发-定时任务的使用
  • Intervention/image 图片处理扩展包的安装和使用
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • js作用域和this的理解
  • Less 日常用法
  • Lucene解析 - 基本概念
  • mysql innodb 索引使用指南
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • Node项目之评分系统(二)- 数据库设计
  • node学习系列之简单文件上传
  • npx命令介绍
  • tweak 支持第三方库
  • Vue ES6 Jade Scss Webpack Gulp
  • 番外篇1:在Windows环境下安装JDK
  • 复杂数据处理
  • 给新手的新浪微博 SDK 集成教程【一】
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 聚簇索引和非聚簇索引
  • 老板让我十分钟上手nx-admin
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 你真的知道 == 和 equals 的区别吗?
  • 如何进阶一名有竞争力的程序员?
  • 跳前端坑前,先看看这个!!
  • 学习笔记:对象,原型和继承(1)
  • 云栖大讲堂Java基础入门(三)- 阿里巴巴Java开发手册介绍
  • AI算硅基生命吗,为什么?
  • 阿里云移动端播放器高级功能介绍
  • ​你们这样子,耽误我的工作进度怎么办?
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (70min)字节暑假实习二面(已挂)
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (附源码)spring boot校园健康监测管理系统 毕业设计 151047
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (七)Java对象在Hibernate持久化层的状态
  • (转) Face-Resources
  • (转)setTimeout 和 setInterval 的区别
  • .NET Core 实现 Redis 批量查询指定格式的Key