AI 技术讲座精选:如何创建简易且能分辨垃圾邮件的ML分类器

在本篇教程中,我们会先提出要解决的问题,然后再利用名为朴素贝叶斯分类器(NaiveBayes Classifier)的机器学习技术解决相应的问题,非常简单。本篇教程需要读者具备编程和数据方面的相关经验,但不必具备机器学习方面的经验。

垃圾邮件的检测

在公司中,你是一位为数以百万计用户提供邮件服务的软件工程师。

最近,垃圾邮件问题十分棘手并且已经导致部分客户流失。然而,当前的垃圾邮件过滤器只能筛选出那些之前被用户被标记过的垃圾邮件,垃圾邮件发送者也变得越来越狡猾。为了防止客户流失,你的任务就是提前预测出当前正在发送的邮件是否为垃圾邮件。

训练并测试数据

为了创建出预测垃圾邮件的算法,你必须让程序知道什么样的邮件是垃圾邮件(以及什么样的邮件是正常的邮件)。幸运的是,你有用户先前标记的所有垃圾邮件。你还需要找到测试垃圾邮件过滤器准确性的方法。其中一个想法就是利用训练垃圾软件过滤器的数据对其进行测试。但是,这种做法会带来机器学习过程中的过度拟合问题,也就意味着你的模型太过偏向于数据的训练。因此,当其处于此训练集以外的数据中时,运行结果不会太理想。避免这种结果的普遍做法是从训练数据和测试数据中分别抽取70%和30%的标记数据。这么做能够保证其是在测试不同的数据而非训练数据。你一定要注意,数据集中不能全是垃圾邮件,既要有垃圾邮件也要有正常的邮件。如果的确想要与真正的邮件数据极度相似的训练数据的话,我在帖子底端给出了一个很好的数据集链接,你可以参考一下。

贝叶斯定理(Bayes’ Theorem)

贝叶斯定理的数学表达式,如下所示:

从本质上来说,贝叶斯定理的数学表达式为那些无法直接计算的条件概率提供了便捷的途径。例如,如果你想计算某些人在某个年龄段罹患癌症的概率,但是你只有关于癌症年龄分部的数据,那么就可以把这些数据放进贝叶斯定理的数学表达式中,而不必进行全国性的研究。如果数据理论把你弄得晕头转向,完全不必担心,当它转化为代码时会更有意义的。不过,我衷心地建议你,如果无法理解许多逻辑谬误的基础贝叶斯定理的话,稍后请重新阅读一下这一部分,然后试着理解该定理。

朴素贝叶斯分类器

对于我们的问题,我们可以把A设定为垃圾邮件的概率,B设定为邮件内容。如果P(A|B)>P(¬A|B),那么我们就可以把邮件归类为垃圾邮件,反之就可以把相应的邮件归类为正常邮件。请注意,贝叶斯定理的结果是两边都以P(B)为除数,为了方便比较,我们把P(B)从方程式中去掉。现在方程式是这样的:P(A)*P(B|A) > P(¬A)*P(B|¬A)。计算P(A)和P(¬A)并不难,它们只是训练集中垃圾邮件和正常邮件的百分比:

#runs once on training data def train: total = 0 numSpam = 0 for email in trainData: if email.label == SPAM: numSpam += 1 total += 1 pA = numSpam/(float)total pNotA = (total — numSpam)/(float)total

更难计算的部分是P(B|A)和 P(B|¬A)。为了计算这些数据,我们准备利用词袋模型。词袋模型是一个非常简单的模型,它把一段文本当作单个词的包(a bag of individual words),顺序并不重要。对于每个单词,我们都分别计算它出现在垃圾邮件和正常邮件中次数的百分比。我们称这种概率为P(B_i|A_x)。我们需要用一个具体的实例来计算P(free | spam),我们计算free这个词在所有垃圾邮件中出现次数的总和,然后除以垃圾文件中所有词的总数。虽然这些是静态值,但是我们可以在训练过程中计算出这些值。

#runs once on training data def train: total = 0 numSpam = 0 for email in trainData: if email.label == SPAM: numSpam += 1 total += 1 processEmail(email.body, email.label) pA = numSpam/(float)total pNotA = (total — numSpam)/(float)total#counts the words in a specific email def processEmail(body, label): for word in body: if label == SPAM: trainPositive[word] = trainPositive.get(word, 0) + 1 positiveTotal += 1 else: trainNegative[word] = trainNegative.get(word, 0) + 1 negativeTotal += 1#gives the conditional probability p(B_i | A_x) def conditionalWord(word, spam): if spam: return trainPositive[word]/(float)positiveTotal

return trainNegative[word]/(float)negativeTotal

只要知道每个单词i的P(B_i|A_x)值的结果,我们就能得到全部邮件的P(B|A_x)。请注意,在初始训练的时候,我们无法获得P(B|A_x)值的结果,只能在分类的时候获取该数值。

#gives the conditional probability p(B | A_x)

def conditionalEmail(body, spam): result = 1.0 for word in body: result *= conditionalWord(word, spam) return result

最终,我们获得了需要进行整合的所有元件。我们所需的最后一部分就是调用每封邮件并且利用我们之前的功能对邮件进行分类。

#classifies a new email as spam or not spam def classify(email): isSpam = pA * conditionalEmail(email, True) # P (A | B) notSpam = pNotA * conditionalEmail(email, False) # P(¬A | B) return isSpam > notSpam

祝贺你!你已经成功地从头开始编码了一个朴素贝叶斯分类器!

可是,你仍需要做一些改进以使分类器达到最佳运行状态而且没有错误:

拉普拉斯平滑方法(Laplace Smoothing):

我们未曾提及的一件事就是:如果分类邮件中出现了一个从未在训练集中出现过的单词,接下来会发生什么。我们需要添加一个平滑因子来处理这种情况。最好的例证就是在修改过的代码下面添加平滑因子alpha,如图所示:

#gives the conditional probability p(B_i | A_x) with smoothing def conditionalWord(word, spam): if spam: return (trainPositive.get(word,0)+alpha)/(float)(positiveTotal+alpha*numWords) return (trainNegative.get(word,0)+alpha)/(float)(negativeTotal+alpha*numWords)

对数空间函数(Log-Space)

当前的实现方法非常依赖于浮点乘法。为了规避所有可能的问题,我们通常会乘以非常小的数,函数通常在方程式中执行对数运算进而将所有的乘法运算转换成加法运算。我未曾在示例代码中执行这种函数,但是强烈建议你在实践中运用一下这种函数。

TF-IDF算法

总体来说,文本分类器的词包模型是相当朴素的并且可以通过TF-IDF这样的算法对其进行优化处理。

N-Grams算法

我们能进行的另一个优化处理,不仅仅只是计算单个词的概率。在N-Grams技术中,设想其是一个拥有N个连续单词的集并且利用他们计算概率。因为在英语中1-gram 中的‘good’传达的意思并不是the 2-gram 中的‘not good’。

Tokenization(符号化)

其中一件非常有意思的事情就是,你是如何分类不同的单词的。例如,Free、free和FREE这是三个相同的单词吗?对于标点又如何处理呢?

请注意,编写示例代码是为了最优化教学,而不是为了运行这些代码。这些清晰、简单地改进方法能够大幅地提升代码的运行速度。

示例数据集:

https://spamassassin.apache.org/publiccorpus/

本文由 AI100 编译,转载需得到本公众号同意。


编译:AI100

原文链接:https://hackernoon.com/how-to-build-a-simple-spam-detecting-machine-learning-classifier-4471fe6b816e


原文发布于微信公众号 - AI科技大本营(rgznai100)

原文发表时间:2017-04-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ATYUN订阅号

【学术】从一个简单的模型开始,可以让机器学习更高效

AiTechYun 编辑:xiaoshan ? 要创建通用人工智能,必须首先掌握逻辑回归 从基础开始 在试图发展对世界的科学认识的时候,大多数的领域在探索重要的...

4237
来自专栏数据派THU

精选 Github 近期13款开源工具包!(附数据集、链接)

本文共1700字,建议阅读6分钟。 本文为你精选近期Github上的13款深度学习开源工具包和数据集,一起Star和Fork吧~

1928
来自专栏机器学习算法与Python学习

干货|谷歌大规模机器学习:模型训练、特征工程和算法选择

关键字全网搜索最新排名 【机器学习算法】:排名第一 【机器学习】:排名第二 【Python】:排名第三 【算法】:排名第四 谷歌机器学习:实际应用技巧 ? ? ...

7885
来自专栏数据派THU

13张动图助你彻底看懂马尔科夫链、PCA和条件概率!

[ 导读 ]马尔科夫链、主成分分析以及条件概率等概念,是计算机学生必学的知识点,然而理论的抽象性往往让学生很难深入地去体会和理解。而本文,将这些抽象的理论概念,...

1191
来自专栏人工智能LeadAI

用Q-Learning算法实现无人车智能代理程序

优达学城的第四个项目,通过Q-Learning算法来实现一个简单的无人车代驾程序。 先来一张训练过程的动图。 ? 01 需求分析 一个无人车需要满足的最基本需...

3716
来自专栏AI研习社

机器学习者必知的 5 种深度学习框架

本文为雷锋字幕组编译的技术博客,原标题 The 5 Deep Learning Frameworks Every Serious Machine Learner...

1733
来自专栏新智元

谷歌开源最大手动注释视频数据集和 TensorFlow 模型性能调优工具

【新智元导读】谷歌再度开放Youtube视频数据集——Youtube边界框(YouTube-BoundingBoxes),含23类共500万手动注释的、紧密贴合...

4478
来自专栏MixLab科技+设计实验室

写给设计师的人工智能指南:如何找出相似的文章

聊聊文本挖掘中的 “找出相似的文章”, 为“推荐系统”做准备。 以下为正文。 ---- 先了解下文本挖掘的一般过程。 如何让计算机读懂一段文字? 本质上要解决的...

41610
来自专栏人工智能头条

本周必看 | 7月ML&Python 最佳开源项目Top 10 :从几百个项目中脱颖而出,都在收藏!

【导读】七月就要结束了,在即将到来的 7 月最后一个周末,人工智能头条为大家整理了本月 ML 和 Python 最受欢迎的十大开源项目。就算放假在家也可以知道大...

1283
来自专栏新智元

谷歌大规模机器学习:模型训练、特征工程和算法选择 (32PPT下载)

【新智元导读】在 ThingsExpo 会议上,谷歌软件工程师 Natalia Ponomareva 作了有关如何在大规模机器学习中取得成功的讲座。Natali...

40010

扫码关注云+社区

领取腾讯云代金券