垃圾邮件分类 机器学习_如何构建简单的检测垃圾邮件的机器学习分类器

垃圾邮件分类 机器学习

垃圾邮件分类 机器学习_如何构建简单的检测垃圾邮件的机器学习分类器_第1张图片

在本教程中,我们将首先提出一个问题,然后继续使用称为Naive Bayes分类器的机器学习技术展示一个简单的解决方案。 本教程需要一点编程和统计经验,但是不需要任何以前的机器学习经验。

垃圾邮件检测

您在一家为数百万人提供电子邮件服务的公司中担任软件工程师。 最近,垃圾邮件一直是一个主要问题,已导致您的客户离开。 您当前的垃圾邮件过滤器只会过滤出客户先前标记为垃圾邮件的电子邮件。 但是,垃圾邮件发送者变得越来越聪明,为了阻止您的客户离开,您被分配了预测电子邮件是否为垃圾邮件的任务。

培训和测试数据

为了为此创建算法,您需要教您的程序垃圾邮件的外观(非垃圾邮件的外观)。 幸运的是,您有所有以前被客户标记为垃圾邮件的电子邮件。 您还需要一种测试垃圾邮件过滤器准确性的方法。 一种想法是对您用于训练的相同数据进行测试。 但是,这可能会导致ML中的一个主要问题,即过度拟合 这意味着您的模型过于偏向训练数据,并且可能无法在该训练集之外的元素上很好地工作。 避免这种情况的一种常见方法是将标记的数据70/30拆分以进行培训/测试。 这样可以确保您测试的数据与培训的数据不同。 重要的是要注意,您需要在数据集中混合使用垃圾邮件和非垃圾邮件数据,而不仅仅是垃圾邮件。 您确实希望您的训练数据尽可能与真实的电子邮件数据相似,我在这篇文章的底部链接了一个很好的数据集。

贝叶斯定理

贝叶斯定理在数学上表示为:

垃圾邮件分类 机器学习_如何构建简单的检测垃圾邮件的机器学习分类器_第2张图片 https://zh.wikipedia.org/wiki/贝叶斯'_theorem

从本质上讲,它为我们提供了一种在无法直接测量条件概率的情况下计算条件概率的技巧。 例如,如果您要计算某人年龄的患癌机会,而不是进行全国性研究,则只需获取有关年龄分布和癌症的现有统计数据,然后将其插入贝叶斯定理即可。 不用担心统计理论是否令人困惑,将其转换为代码时会更有意义。 但是,我还是建议您回过头再尝试稍后再理解它,因为未能理解贝叶斯定理是许多逻辑谬论的根源。

朴素贝叶斯分类器

对于我们的问题,我们可以将A设置为电子邮件为垃圾邮件的可能性,将B设置为电子邮件的内容。 如果P(A | B)> P( ¬A | 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 )。 为了计算这些,我们将使用单词袋模型 。 这是一个非常简单的模型,将一段文本视为一包单独的单词,而无需注意其顺序。 对于每个单词,我们计算它在垃圾邮件和非垃圾邮件中出现的百分比。 我们称这个概率为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

要获得整个电子邮件的P(B | A_x),我们只需对电子邮件中每个单词i取P(B_i | 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 conditionalEmail

我们终于有了将它们组合在一起所需的所有组件。 我们需要的最后一块是分类器,该分类器会针对每封电子邮件进行调用,并使用我们之前的功能对其进行分类。

#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

恭喜你! 您已经成功地从头开始编写了Naive Bayes分类器!

但是,您需要进行一些更改以使其最佳运行并且没有错误:

拉普拉斯平滑:
我们没有提到的一件事是,如果您要分类的电子邮件中的单词不在您的训练集中,将会发生什么。 为了处理这种情况,我们需要添加一个平滑因子。 最好的示例在下面的修改代码中,其中添加了平滑因子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)

日志空间
我们当前的实现严重依赖浮点乘法。 为了避免与很小的数字相乘的所有潜在问题,通常对等式执行对数以将所有乘法转换为加法。 我没有在示例代码中实现此功能,但在实践中强烈建议这样做。

特遣部队
总体而言,用于文本分类的单词袋模型相当幼稚,可以通过诸如TF-IDF之类的其他东西加以改进。

N克
我们可以做的另一项改进不仅是计算单个单词。 N-Grams是一种技术,其中可以考虑N个连续单词的集合并使用它们来计算概率。 这是有道理的,因为在英语中1克“好”传达的东西不同于2克“不好”​​。

请注意,示例代码是为了获得最佳教学效果而非性能而编写的。 有一些明显的,微不足道的更改可以极大地提高其性能。

样本数据集: https : //spamassassin.apache.org/publiccorpus/

如果您喜欢本文,请推荐并跟随作者以帮助其他人看到它!

翻译自: https://hackernoon.com/how-to-build-a-simple-spam-detecting-machine-learning-classifier-4471fe6b816e

垃圾邮件分类 机器学习

你可能感兴趣的:(python,机器学习,人工智能,java,深度学习)