VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > Python基础教程 >
  • 基于C#的机器学习--垃圾邮件过滤(2)

Email垃圾邮件过滤

  我们已经走了很长的路,最终在c#中构建了我们的第一个ML模型。在本节中,我们将训练逻辑回归和朴素贝叶斯分类器来将电子邮件分为垃圾邮件和非垃圾邮件。我们将使用这两种学习算法来进行交叉验证,以更好地了解我们的分类模型在实践中的表现。如前一章所简要讨论的,在k-fold交叉验证中,训练集被划分为k个大小相等的子集,其中一个子集作为验证集,其余的k-1子集用于训练模型。然后重复这个过程k次,在每次迭代中使用不同的子集或折叠作为测试的验证集,然后对相应的k验证结果求平均值以报告单个估计。
  让我们首先看看如何使用Accord在c#中用逻辑回归来实例化交叉验证算法。代码如下:

复制代码
 1 var cvLogisticRegressionClassifier = CrossValidation.Create<LogisticRegression, 
 2                 IterativeReweightedLeastSquares<LogisticRegression>, double[], int>(
 3                     // 折叠数量    
 4                     k: numFolds,
 5                     // 学习算法    
 6                     learner: (p) => new IterativeReweightedLeastSquares<LogisticRegression>()
 7                     {
 8                         MaxIterations = 100,
 9                         Regularization = 1e-6
10                     },
11                     // 使用0 - 1损失函数作为成本函数 
12                     loss: (actual, expected, p) => new ZeroOneLoss(expected).Loss(actual),
13                     // 合适的分类器    
14                     fit: (teacher, x, y, w) => teacher.Learn(x, y, w),
15                     // 输入    
16                     x: input,
17                     // 输出    
18                     y: output
19                 );
20 // 运行交叉验证
21 var result = cvLogisticRegressionClassifier.Learn(input, output);
复制代码

  让我们更深入地看看这段代码。通过提供要训练的模型类型、适合模型的学习算法类型、输入数据类型和输出数据类型,我们可以使用静态create函数创建一个新的交叉验证算法。对于这个例子,我们创建了一个新的交叉验证算法,以逻辑回归为模型,以IterativeReweightedLeastSquares作为学习算法,以双数组作为输入类型,以整数作为输出类型(每个标签)。您可以尝试使用不同的学习算法来训练逻辑回归模型。在协议。您可以选择使用随机梯度下降算法(LogisticGradientDescent)作为适合逻辑回归模型的学习算法。
  对于参数,我们可以为k-fold交叉验证(k)、带有自定义参数的学习方法(learner)、选择的损失/成本函数(loss)和一个知道如何使用学习算法(fit)来拟合模型的函数(x)、输入(x)和输出(y)指定折叠数。为了在本节中进行说明,我们为k-fold交叉验证设置了一个相对较小的数字3。此外,对于最大的迭代,我们选择了一个相对较小的数字,100,而对于迭代加权最小二乘学习算法的正则化,我们选择了一个相对较大的数字,le-6或1/1,000,000。对于损耗函数,我们使用一个简单的0 - 1损耗函数,它为正确的预测分配0,为错误的预测分配1。这就是我们的学习算法试图最小化的代价函数。所有这些参数都可以进行不同的调优。我们可以选择一个不同的损耗/成本函数,k折叠交叉验证中使用的折叠数,以及学习算法的最大迭代次数和正则化次数。我们甚至可以使用不同的学习算法来适应逻辑回归模型,比如LogisticGradientDescent,它将迭代地尝试找到损失函数的局部最小值。
  我们可以用同样的方法训练朴素贝叶斯分类器,用k次交叉验证。使用朴素贝叶斯学习算法进行k-fold交叉验证的代码如下:

复制代码
 1 var cvNaiveBayesClassifier = CrossValidation.Create<NaiveBayes<BernoulliDistribution>,
 2                 NaiveBayesLearning<BernoulliDistribution>, double[], int>(
 3                     // 折叠的数量
 4                     k: numFolds,
 5                     // 二项分布的朴素贝叶斯分类器
 6                     learner: (p) => new NaiveBayesLearning<BernoulliDistribution>(),
 7                     // 使用0 - 1损失函数作为成本函数
 8                     loss: (actual, expected, p) => new ZeroOneLoss(expected).Loss(actual),
 9                     // 合适的分类器
10                     fit: (teacher, x, y, w) => teacher.Learn(x, y, w),
11                     // 输入
12                     x: input,
13                     // 输出
14                     y: output
15                 );
16 // 运行交叉验证
17 var result = cvNaiveBayesClassifier.Learn(input, output);
复制代码

  之前的逻辑回归模型代码与这段代码的唯一区别是我们选择的模型和学习算法。我们使用NaiveBayes作为模型,NaiveBayesLearning作为学习算法来训练我们的NaiveBayes分类器,而不是使用LogisticRegression和IterativeReweightedLeastSquares。由于所有的输入值都是二进制的(0或1),所以我们使用BernoulliDistribution作为我们的朴素Byes分类器模型。
  当你运行这段代码,你应该看到一个输出如下:

 

 

   在下面讨论模型验证方法的小节中,我们将进一步研究这些数字所代表的内容。为了尝试不同的ML模型。可以使用我们前面讨论过的逻辑回归模型代码来替换它们,或者也可以尝试选择不同的学习算法使用。

验证分类模型

  我们使用Accord.Net Framework在c#中建立了第一个ML模型。然而,我们还没有完全完成。如果我们更仔细地查看以前的控制台输出,就会发现有一件事非常令人担忧的情形。训练误差约为0.03,而验证误差约为0.26。这意味着我们的分类模型在训练集中正确预测了100次中的87次,而在验证或测试集中正确预测了100次中的74次。这是一个典型的过度拟合的例子,其中模型与训练集非常接近,以至于它对未预见数据集的预测是不可靠和不可预测的。如果我们将这个模型应用到垃圾邮件过滤系统中,那么实际用于过滤垃圾邮件的模型性能将是不可靠的,并且会与我们在训练集中看到的有所不同。
  过度拟合通常是因为模型对于给定的数据集来说太复杂,或者使用了太多的参数来拟合模型。我们在上一节中建立的朴素贝叶斯分类器模型的过拟合问题很可能是由于我们用来训练模型的复杂性和特征的数量。
  如果再次查看上一节末尾的控制台输出,我们可以看到用于训练朴素贝叶斯模型的特性的数量是2,212。这太多了,考虑到我们只有约4200封电子邮件记录,在我们的样本集只有三分之二(或大约3000条记录)被用来训练我们的模型(这是因为我们使用三倍交叉验证,只有两三个折叠用作训练集在每个迭代)。为了解决这个过拟合问题,我们必须减少用于训练模型的特性的数量。为了做到这一点,我们可以过滤掉那些不经常出现的项。完成此任务的代码,如下所示:

复制代码
1 // 改变特征的数量以减少过度拟合
2     int minNumOccurences = 1;
3     string[] wordFeatures = indexedSpamTermFrequencyDF.Where(
4         x => x.Value.GetAs<int>("num_occurences") >= minNumOccurences
5     ).RowKeys.ToArray();
6 Console.WriteLine("Num特征选择: {0}", wordFeatures.Count());
复制代码

  从这段代码可以看出,我们在前一节中构建的Naive Bayes分类器模型至少使用了垃圾邮件中出现的所有单词。
  如果我们查看垃圾邮件中的单词频率,大约有1400个单词只出现一次(查看在数据分析步骤中创建的spam-frequencies.csv文件)。直观地说,那些出现次数少的单词只会产生噪音,对我们的模型来说没有多少信息可以学习。这告诉我们,当我们在前一节中最初构建分类模型时,我们的模型将暴露在多少噪声中。
  现在我们知道了这个过度拟合问题的原因,让我们来修复它。让我们用不同的阈值来选择特征。我们已经尝试了5、10、15、20和25,以使垃圾邮件中出现的次数最少(也就是说,我们将minNumOccurrences设置为5、10、15等等),并使用这些阈值训练Naive Bayes分类器。
  首先,朴素贝叶斯分类器的结果至少出现5次,如下图所示:

 

 

   首先,朴素贝叶斯分类器的结果至少出现10次,如下图所示:

  首先,朴素贝叶斯分类器的结果至少出现15次,如下图所示:

  首先,朴素贝叶斯分类器的结果至少出现20次,如下图所示:

  从这些实验结果可以看到,当我们增加了最小数量的单词出现次数和减少相应的特性数量用来训练模型, 训练误差与验证误差之间的差距减小,训练误差开始与验证误差近似。当我们解决过拟合问题时,我们可以更加确信模型将如何处理未预见的数据和生产系统。
  现在我们已经介绍了如何处理过拟合问题,我们希望看看更多的模型性能度量工具:
    Confusion matrix(混淆矩阵): 混淆矩阵是一个表,它告诉我们预测模型的整体性能。每一列表示每个实际类,每一行表示每个预测类。对于二元分类问题,混淆矩阵是一个2×2的矩阵,其中第一行表示消极预测,第二行表示积极预测。第一列表示实际的否定,第二列表示实际的肯定。下表说明了一个二元分类问题的混淆矩阵中的每个单元格代表什么。

      

    True Negative (TN) :

      TP、True Positive 真阳性:预测为正,实际也为正
      FP、False Positive 假阳性:预测为正,实际为负
      FN、False Negative 假阴性:预测与负、实际为正
      TN、True Negative 真阴性:预测为负、实际也为负。
    从表中可以看出,混淆矩阵描述了整个模型的性能。在我们的例子中,如果我们看最后一个控制台输出在前面的屏幕截图,显示了控制台输出的逻辑回归分类模型中,我们可以看到,TNs的数量是2847,fn的数量是606,FPs的数量是102,和76 tps的数量是772。根据这些信息,我们可以进一步计算真实阳性率(TPR)、真实负性率(TNR)、假阳性率(FPR)和假阴性率(FNR),如下: 

        

 

      使用前面的例子,我们例子中的真实阳性率是0.56,TNR是0.97,FPR是0.03,FNR是0.44
    Accuracy(准确性):准确性是正确预测的比例。使用与前面示例混淆矩阵相同的表示法,计算精度如下:

       

 

 

 

    准确性是一个经常使用的模型性能指标,但有时它并不能很好地代表整个模型的性能。例如,如果样本集很大程度上是不平衡的,并且,假设在我们的样本集中有5封垃圾邮件和95条火腿,那么一个简单的分类器将每封邮件都归类为火腿,那么它必须有95%的准确率。然而,它永远不会捕捉垃圾邮件。这就是为什么我们需要查看混乱矩阵和其他性能指标,如精度和正确率
    Precision rate(精度):精度是正确的正面预测数量占全部正面预测数量的比例。使用与之前相同的符号,我们可以计算出精度率如下:

      

 

 

 

    如果看看过去的控制台输出之前的截图的逻辑回归分类模型结果,精确率计算的数量除以TPs混淆矩阵,772年,由TPs的总和,FPs, 102年,772年从混淆矩阵,结果是0.88。
    Recall rate(召回率):正确率是正确正面预测的数量占实际阳性总数的比例。这是告诉我们有多少实际的积极案例是由这个模型检索到的一种方式。使用与前面相同的符号,我们可以计算召回率,如下所示:

      

 

 

 

  如果看看过去的控制台输出在前面的截图为我们的逻辑回归分类模式的结果,正确率计算的数量除以TPs混淆矩阵,通过TPs的总和,772年,772年和fn, 606年,混淆矩阵,其结果是0.56。
  有了这些性能指标,我们就可以选择最佳模型。在精度和正确率之间总是存在权衡。与其他模型相比,具有较高准确率的模型召回率较低。对于我们的垃圾邮件过滤问题,如果认为正确地过滤垃圾邮件更重要,并且可以牺牲一些通过用户收件箱的垃圾邮件,那么我们可以优化精度。另一方面,如果认为过滤掉尽可能多的垃圾邮件更重要,即使我们可能会过滤掉一些非垃圾邮件,那么可以优化正确率。选择正确的模型不是一个简单的决定,仔细考虑需求和成功标准是做出正确选择的关键。
  总之,下面是我们可以用来从交叉验证结果和混淆矩阵中计算性能指标的代码:

复制代码
 1 // 运行交叉验证
 2     var result = cvNaiveBayesClassifier.Learn(input, output);
 3 // 训练错误
 4     double trainingError = result.Training.Mean;
 5     //验证错误
 6 double validationError = result.Validation.Mean;
 7 混淆矩阵:真阳性与假阳性和真阴性与假阴性:
 8 // 混淆矩阵
 9 GeneralConfusionMatrix gcm = result.ToConfusionMatrix(input, output);
10 float truePositive = (float)gcm.Matrix[1, 1];
11      float trueNegative = (float)gcm.Matrix[0, 0];
12      float falsePositive = (float)gcm.Matrix[1, 0];
13 float falseNegative = (float)gcm.Matrix[0, 1];
复制代码

  训练与验证(测试)错误:用于识别过拟合问题:

1 // 计算的准确率, 精度, 召回
2 float accuracy = (truePositive + trueNegative) / numberOfSamples;
3 float precision = truePositive / (truePositive + falsePositive);
4 float recall = truePositive / (truePositive + falseNegative);

总结

  在本章中,我们用c#构建了第一个可以用于垃圾邮件过滤的ML模型。我们首先定义并清楚地说明我们要解决的问题以及成功的标准。然后,我们从原始邮件数据中提取相关信息,并将其转换为一种格式,用于数据分析、特征工程和ML模型构建步骤。

  在数据分析步骤中,我们学习了如何应用单一热编码并构建主题行中使用的单词的矩阵表示。

  我们还从数据分析过程中发现了一个数据问题,并了解了如何在数据准备和分析步骤之间来回迭代。

  然后,我们进一步改进了我们的特性集,过滤掉停止单词,并使用正则表达式将非字母数字或非字母单词分隔开。

  有了这个特征集,我们使用逻辑回归和朴素贝叶斯分类器算法建立了第一个分类模型,简要介绍了过度拟合的危险,并学习了如何通过观察准确性、精度和召回率来评估和比较模型性能。

  最后,我们还学习了精度和召回之间的权衡,以及如何根据这些度量和业务需求选择模型。

“老天爷给你的任何机会,你也不会珍惜,更不会深入下去,你认为自己就是穷命,最喜欢通过脉脉阅读免费的职场技巧。如果你还是杠精思维,任何事情,跑上来先论证困难,给自己一个不干不参与的充分理由,那你完了。人生不过是短短十五年的机会,到了四十岁,你还在屌丝堆里,啥也不干,那你没希望了。”

相关教程
关于我们--广告服务--免责声明--本站帮助-友情链接--版权声明--联系我们       黑ICP备07002182号