贝叶斯算法:垃圾邮件过滤

article/2025/10/4 7:57:32

准备
    100封邮件,50封垃圾邮件和50封正常邮件
参考 :
    贝叶斯算法原理

程序过程解释
垃圾邮件分类的数学基础是贝叶斯推断(bayesian inference)。整个程序过程主要有以下几个部分构成:

step 1 : 提取邮件并处理
1、使用 TDirectory.GetFiles(xPath) 获得 xPath 指示的文件夹下的所有文件的路径。
2、用 TStringList 根据路径读取文件内容。
3、使用 Split 方法将TStringList读取的内容以空格和“#13”分割开,并将所有单词放入数组中。

以上三个步骤全部包含在  getEmail(emailClass) 函数 和 processEmail(emailpath) 函数中。

step 2 : 获得在 normal 和 junk中每个单词的频数
这个步骤在代码中只是一个函数 getWordFrequency(emailClass) 。emailClass 表示邮件类别,即 normal 或者 junk 。返回的是一个字典,字典的 key值是单词,value值是这个单词的频数。

注意,这里的频数并不是指这个单词出现了多少次,而是指这个单词在多少封邮件当中出现过。例如:一个单词 sex 出现在3封邮件中,分别出现了5次,6次,4次,则这个单词 sex 的频数我们这里确定为3(因为它出现在3封邮件中),而不是 5 + 6+ 4 = 15 。

step 3 : 计算每个单词的后验概率
这一段代码包含在(某种意义上的)“主函数”当中 :

1、通过step 1和 step 2定义的函数取得 normal 和 junk 中每个单词的频数;
2、创建单词的先验概率字典 GPosteriorProbabilityDict ,并初始化每一个单词的先验概率为0.00;
3、使用 for...in... 循环得到每个单词的先验概率:

     P(S|W) = P(W|S)P(S) / P(W|S)P(S) + P(W|H)P(H)
     
因为 normal 和 junk 的邮件数量相同,所以其先验概率 P(S) 和 P(H) 是相同的,均为 50%, 所以公式简化为 :

     P(S|W) = P(W|S) / P(W|S) + P(W|H)

在代码中 P(W|S) 用 xJunkPro 变量表示, P(W|H)用 xNormalPro 表示。

如果当前单词在某个类别当中没有出现过,则可规定这个单词在这个类别中的后验概率是 0.01。

step 4 : 分类函数
这步骤主要体现在  testEmail(emailpath, threshold = 0.7) 函数中。email 参数表示email文件, threshold参数表示阀值,当计算得到的结果大于threshold时表示这是一封垃圾邮件(junk), 否则这是一封正常邮件(normal), 这里默认 threshold = 0.7。

对于给定的测试email,计算过程如下 :

1、使用 processEmail() 函数处理得到这封email的单词集合xWordArr 。
2、将这封邮件中每个单词和它的后验概率放入数组 xPosteriorProbabilityArr 中 ,如果这个单词在字典 GPosteriorProbabilityDict 中并没有出现过,则指定其值为 0.4。
3、按照每个单词的概率值从小到大排序。
4、最后,计算联合概率。这里只取出先验概率最大的前15个词计算联合概率,公式为:

                                

这里  用 变量xFracTop 在for...in...循环中累乘表示, 用变量xFracBottom累乘表示 。 

6、返回判定结果,如果xFracTop / (xFracTop + xFracBottom) 的值大于阀值threshold则判定为junk, 否则判定为 normal 。

step 5 : 准备工作完成,开始测试
对新收到的邮件进行测试,将收到的邮件存为txt文件,把路径赋给testEmail()函数中进行测试。然后,就等待判定结果。

完整代码

uses System.Generics.Collections ,System.Generics.Defaults;

type
  TArrayB = array of TArray<string> ;

# step 1 : get E-mail and process them

class function TJunkBayes.processEmail(emailpath: string): TArray<string> ;
var
  xWordLst: TStringList ;
  xWordArr: TArray<string> ;
const xSep: array[0..1] of string = (' ' ,#13);
begin
  xWordLst := TStringList.Create ;
  xWordLst.LoadFromFile(emailpath) ;
  xWordArr := xWordLst.Text.Split(xSep) ;
  Result := xWordArr ;
end;

class function TJunkBayes.getEmail(emailClass: string): TArrayB ;
var
  xPath: string ;
  I : Integer ;
  xFileArr: TArray<string> ;
  xEmailArr : TArrayB ;
  xLen: Integer ;
begin
  xPath := g_BayesPath + '\' + emailClass ;
  xFileArr := TDirectory.GetFiles(xPath) ;
  xLen := Length(xFileArr) ;
  SetLength(xEmailArr ,xLen);
  for I := Low(xFileArr) to High(xFileArr) do
    begin
      xEmailArr[I] := processEmail(xFileArr[I]) ;
    end;
  Result := xEmailArr ;
end;

# step 2 : get word frequency of the email's class

class function TJunkBayes.getWordFrequency(emailClass: string): TDictionary<string,Integer> ;
var
  xWordFrequencyDict : TDictionary<string ,Integer> ;
  xEmailArr: TArrayB ;
  I ,k: Integer;
  xWord : string ;
  xWordLst: TStringList ;
begin
  xEmailArr := getEmail(emailClass) ;
  xWord := '';
  xWordLst := TStringList.Create ;
  xWordFrequencyDict := TDictionary<string,Integer>.Create();
  for I := Low(xEmailArr) to High(xEmailArr) do  //遍历每封邮件
    begin
      xWordLst.Clear ;
      for k := Low(xEmailArr[I]) to High(xEmailArr[I]) do  //遍历一封邮件里的内容
        begin
          xWord := Trim(LowerCase(xEmailArr[I][k])) ;
          if xWord = '' then Continue ;
          if xWordLst.IndexOf(xWord) = -1 then
            xWordLst.Add(xWord) ;
        end;
      for k := 0 to xWordLst.Count - 1 do
        begin
          xWord := xWordLst[k] ;
          try
            xWordFrequencyDict.Items[xWord] := xWordFrequencyDict.Items[xWord] + 1 ;
          except
            xWordFrequencyDict.Add(xWord ,1) ;
          end;
        end;
    end;
  Result := xWordFrequencyDict ;
end; 

# step 4 : calculate classified result of test email

class function TJunkBayes.TestEmail(emailpath: string ;Threshold: Double) : Boolean ;
var
  xWordArr: TArray<string> ;
  xWord : string ;
  xProbability : Double ;
  xPosteriorProbabilityArr: array of Double ;
  xCount: Integer ;
  I : Integer ;
  xFracTop,xFracBottom : Double ;
begin
  Result := False ;
  xWordArr := processEmail(emailpath) ;
  SetLength(xPosteriorProbabilityArr ,Length(xWordArr));
  xCount := 0 ;
  for xWord in xWordArr do
    begin
      try
        xProbability := GPosteriorProbabilityDict[xWord] ;
      except //当这个单词不存在时
        xProbability := 0.4 ;
      end;
      xPosteriorProbabilityArr[xCount] := xProbability ;
      xCount := xCount + 1;
    end;
  TArray.Sort<Double>(xPosteriorProbabilityArr); //从小到大排序
  xFracTop := 1 ;
  xFracBottom := 1 ;
  for I := High(xPosteriorProbabilityArr) downto Length(xPosteriorProbabilityArr) - 15 do
    begin
      xFracTop := xFracTop * xPosteriorProbabilityArr[I] ;
      xFracBottom := xFracBottom * (1 - xPosteriorProbabilityArr[I]) ;
    end;
  if (xFracTop / (xFracTop + xFracBottom) > Threshold) then
    Result := True
  else
    Result := False ;
end;

#step 3: calculate posterior probability

class procedure TJunkBayes.CalculateWordPosteriorProbability ;
var
  xNormalDict: TDictionary<string ,Integer> ;
  xJunkDict: TDictionary<string ,Integer> ;
  xNormalEmailCount ,xJunkEmailCount: Integer ;
  xWord : string ;
  I: Integer;
  xNormalPro ,xJunkPro : Double ;
begin
  xNormalEmailCount := Length(TDirectory.GetFiles(g_BayesPathNormal)) ;
  xJunkEmailCount := Length(TDirectory.GetFiles(g_BayesPathJunk)) ;
  GPosteriorProbabilityDict := TDictionary<string ,Double>.Create() ;
  //正常邮件集 里所有的单词和频数
  xNormalDict := getWordFrequency('NormalBayes') ;
  //垃圾邮件集里所有的单词和频数
  xJunkDict := getWordFrequency('JunkBayes') ;
  for xWord in xNormalDict.Keys do
    begin
      GPosteriorProbabilityDict.Add(xWord ,0);
    end;
  for xWord in xJunkDict.Keys do
    begin
      try
        GPosteriorProbabilityDict.Add(xWord ,0);
      except
      end;
    end;
  for xWord in GPosteriorProbabilityDict.Keys do
    begin
      try
        xNormalPro := xNormalDict[xWord] / xNormalEmailCount ;
      except
        xNormalPro := 0.01 ;
      end;
      try
        xJunkPro := xJunkDict[xWord] / xJunkEmailCount ;
      except
        xJunkPro := 0.01 ;
      end;
      GPosteriorProbabilityDict[xWord] := xJunkPro / (xNormalPro + xJunkPro) ;
    end;
end;

#step 5 : test start

调用以下两个过程

TJunkBayes.CalculateWordPosteriorProbability ;
TJunkBayes.TestEmail('testemailpath' ,0.7) ;  


http://chatgpt.dhexx.cn/article/hRSh2usI.shtml

相关文章

毕业设计-基于深度学习的垃圾邮件过滤系统的设计与实现

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

机器学习:朴素贝叶斯算法与垃圾邮件过滤

简介 贝叶斯算法是由英国数学家托马斯贝叶斯提出的&#xff0c;这个算法的提出是为了解决“逆向概率”的问题。首先我们先来解释下正向概率与逆向概率的含义&#xff1a; 正向概率&#xff1a;假设一个箱子里有5个黄色球和5个白色球&#xff0c;随机从箱子里拿出一个球&#…

朴素贝叶斯算法--垃圾邮件过滤

文章目录 一、朴素贝叶斯概述1、贝叶斯决策理论2、条件概率3、朴素贝叶斯4、朴素贝叶斯一般过程 二、朴素贝叶斯算法--垃圾邮件1、准备数据&#xff1a;从文本中构建词向量2、训练算法&#xff1a;从词向量计算概率3、测试算法&#xff1a;根据现实情况修改分类器5、垃圾邮件分…

机器学习-朴素贝叶斯过滤垃圾邮件

一、朴素贝叶斯实现垃圾邮件分类的原理 什么是朴素贝叶斯算法&#xff1a;用贝叶斯定理来预测一个未知类别的样本属于各个类别的可能性,选择可能性最大的一个类别作为该样本的最终类别。 用这个算法处理垃圾邮件就可以理解为&#xff1a;用贝叶斯定理来预测一封由若干个单词组成…

机器学习项目(一)——垃圾邮件的过滤技术

一、垃圾邮件过滤技术项目需求与设计方案 二、数据的内容分析 &#xff08;1、是否为垃圾邮件的标签&#xff0c;spam——是垃圾邮件&#xff1b;ham——不是垃圾邮件&#xff09; &#xff08;2、邮件的内容分析——主要包含&#xff1a;发件人、收件人、发件时间以及邮件的内…

多线程的闭锁和栅栏

多线程的闭锁和栅栏 JAVA并发包中有三个类用于同步一批线程的行为&#xff0c;分别是闭锁&#xff08;Latch&#xff09;&#xff0c;信号灯&#xff08;Semaphore&#xff09;和栅栏&#xff08;CyclicBarrier&#xff09;。这里我们主要来介绍一下&#xff1a; 闭锁&#x…

分布式锁(Distributed Lock)理论介绍

在多线程环境中&#xff0c;线程之间通常使用互斥锁实现共享资源的独占访问。在多进程环境&#xff0c;特别是分布式环境&#xff0c;常使用分布式锁来实现共享资源的独占访问。简单来说&#xff0c;分布式锁就是指在分布式环境下&#xff0c;通过加解锁实现多节点对共享资源的…

迟滞电路 平稳欠压和过压闭锁

下述的等式假设比较器输入端的输入偏置电流为0&#xff0c;而示例只考虑了电阻比&#xff0c;而未考虑绝对值。比较器输入同时具有输入失调电压(VOS)、参考误差&#xff08;也可以与VOS合并&#xff09;&#xff0c;以及输入偏置电流或漏电流(ILK)。如果分压器偏置电流&#xf…

偏向锁

流程讲解 当JVM启用了偏向锁模式&#xff08;JDK6以上默认开启&#xff09;&#xff0c;新创建对象的Mark Word中的Thread Id为0&#xff0c;说明此时处于可偏向但未偏向任何线程&#xff0c;也叫做匿名偏向状态(anonymously biased)。 偏向锁逻辑 1.线程A第一次访问同步块时&…

什么是间隙锁?

什么是间隙锁? 间隙锁是一个在索引记录之间的间隙上的锁。 间隙锁的作用 保证某个间隙内的数据在锁定情况下不会发生任何变化。比如mysql默认隔离级别下的可重复读(RR)。 当使用唯一索引来搜索唯一行的语句时,不需要间隙锁定。如下面语句的id列有唯一索引,此时只会对id值…

锁消除、锁粗化、偏向锁、适应性锁

文章目录 锁消除锁粗化偏向锁适应性锁 锁消除 锁消除是JIT编译器对内部锁实现的一种优化。JIT可以借助逃逸分析来判断同步块的锁对象是否只是被一个线程访问&#xff0c;如果是的话&#xff0c;则在编译期间不生成内部锁的申请与释放对应的机器码&#xff0c;即消除了锁的使用…

多线程并发之CountDownLatch(闭锁)使用详解

专题相关文章&#xff1a; 从内存可见性看Volatile、原子变量和CAS算法 多线程并发之CountDownLatch(闭锁)使用详解 多线程并发之显示锁Lock与其通信方式Condition源码解读 多线程并发之读写锁(ReentranReadWriteLock&ReadWriteLock)使用详解 多线程并发之线程池Executor与…

【ABAQUS】什么是剪切闭锁?剪切闭锁会导致什么?

“完全积分”是指当单元具有规则形状时&#xff0c;对单元刚度矩阵中的多项式项进行精确积分所需的高斯点数。对于六面体和四边形元素&#xff0c;“规则形状”意味着边缘是直的&#xff0c;并以直角相交&#xff0c;任何边缘节点都位于边缘的中点。 完全积分的线性元素在每个…

电力“五防”闭锁系统

&#xff08;转载&#xff09; 电力“五防”闭锁系统 随着电子技术在各个行业领域的飞速发展&#xff0c;电力的“五防”也将发生革命性的转变。现代电力系统规模不断扩大&#xff0c;从而促使电压的等级也得到了进一步提高。为了使电力系统的安全稳定运行能够得以充分保障&am…

【LB-1A 100V电压回路断相闭锁继电器】

系列型号 LB-1A电压回路断相闭锁继电器 LB-1A闭锁继电器 1 用途 LB-1A型电压回路断相闭锁继电器&#xff08;以下简称继电器&#xff09;是在交流电压回路断线而可能引起继电保护误动作时&#xff0c;对继电保护进行闭锁。该继电器用于中性点非直接接地系统中。 2 结构与工作原…

间隙锁

一.几个基本概念 行锁&#xff1a;给某一行加的锁间隙锁&#xff1a;就是两个值之间的间隙。为了解决幻读问题&#xff0c;InnoDB 只好引入新的锁&#xff0c;也就是 间隙锁 (Gap Lock)。间隙锁Gap,左右都是开区间&#xff0c;间隙锁行锁合称next-key lock,每个 next-key lock…

闭锁,信号量,栅栏

1. 闭锁&#xff08;countDownLatch&#xff09; 1.1. 作用&#xff1a; 相当于一扇门&#xff0c;在闭锁到达结束状态之前&#xff0c;这扇门是关着的&#xff0c;所以的线程都不允许通过&#xff0c;当闭锁到达结束状态&#xff0c;这扇门打开并允许所有的线程通过。在…

visio 2010激活教程

一、下载office2010toolkit.zip 若下载链接失效&#xff0c;手动搜索office2010toolkit http://ys-c.ys168.com/605279628/o4W138W45JIPI5SiuWf5/office2010toolkit.zip二、激活 激活过程中需要关闭office套件

Microsoft Visio Professional 2013 安装步骤

1.打开解压后的文件夹&#xff0c;点击setup.exe安装 2.勾选我接受此协议的条款&#xff0c;继续 3.点击立即安装 4.安装完成&#xff0c;关闭。 5.打开第一步解压的文件夹中破解文件夹&#xff0c;鼠标右键以管理员身份运行 6.点击激活office2013VL 7.激活完成 Microsoft Visi…