数据挖掘与机器学习-WEKA应用技术与实践(第二版)
上QQ阅读APP看书,第一时间看更新

2.3 分类

分类是指得到一个分类函数或分类模型(即分类器),通过分类器将未知类别的数据对象映射到某个给定的类别。

数据分类可以分为两步。第一步建立模型,通过分析由属性描述的数据集,来建立反映其特性的模型。该步骤也称作有监督的学习,基于训练集而导出模型,训练集是已知类别标签的数据对象。第二步使用模型对数据对象进行分类。首先评估模型的分类准确度或其他指标,如果可以接受,才使用它来对未知类别标签的对象进行分类。

预测的目的是从历史数据记录中自动推导出对给定数据的推广描述,从而能够对事先未知类别的数据进行预测。分类和回归是两类主要的预测问题,分类是预测离散的值,回归是预测连续的值。

Weka提供Classify标签页来构建分类器,如图2.39所示。

图2.39 Classify标签页

下面详细介绍Classify标签页的功能。

2.3.1 分类器选择

在Classify标签页的最上部是Classifier(分类器)选项组,选项组内有一个Choose按钮和一个分类器文本框。按钮用于选择Weka提供的分类器,文本框用于显示当前选择的分类器的名称和选项。单击文本框,会弹出一个通用对象编辑器对话框,与过滤器的对象编辑器对话框的功能一样,可以用来设置当前分类器的选项。右击(或在按住Alt键和Shift键的同时单击)分类器文本框,会弹出一个快捷菜单,选择Show properties菜单项可以打开通用对象编辑器对话框,选择Copy configuration to clipboard菜单项可以将当前设置的字符串复制到剪贴板,选择Edit configuration菜单项可以修改设置,选择Enter configuration菜单项可以直接输入设置字符串,使用方法与过滤器的相似。

在Classify标签页的左部有Test options(测试选项)选项组。该选项组用于设置测试模式,并将设置的选项应用到当前选择的分类器中。测试模式分为以下四种。

(1)Use training set(使用训练集):直接将训练集实例用于测试,评估分类器预测类别的性能。这种方式得到的结果往往好于对未知实例的测试结果,不能反映分类器的泛化能力。

(2)Supplied test set(提供测试集):从一个文件中加载一组测试实例,评估分类器预测类别的性能。单击Set按钮会弹出一个对话框,允许用户选择测试集文件。

(3)Cross-validation(交叉验证):通过交叉验证评价分类器。在Folds文本框中输入交叉验证的折数,默认为十折交叉验证。

(4)Percentage split(按比例分割):在数据集中,取出特定百分比的数据用于训练,其余的数据用于测试,评价分类器预测分类的性能。取出的数据量取决于用户在“%”文本框中输入的值,默认取出66%的数据作为训练集。

注意: 无论使用哪种测试模式作为评估方法,输出模型始终都是从全部训练数据中构建而得。

更多的测试选项可以通过单击More options按钮进行设置,如图2.40所示。

图2.40 更多测试选项

对这些测试选项的解释如下。

(1)Output model(输出模型):输出通过完整训练集得到的分类模型,以便能够浏览、可视化等。默认选中此选项。

(2)Output per-class stats(输出每个类别的统计信息):输出每个分类的查准率/查全率以及True/False的统计信息。默认选中此选项。

(3)Output entropy evaluation measures(输出熵评估度量):输出中包括熵评估度量。默认取消选中此选项。

(4)Output confusion matrix(输出混淆矩阵):输出中包含分类器预测得到的混淆矩阵。默认选中此选项。

(5)Store predictions for visualization(存储预测以便可视化):保存分类器的预测结果,以便用于可视化。默认选中此选项。

(6)Error plot point size proportional to margin(错误散点大小正比于预测边际):设置所绘制的错误散点大小是否正比于预测边际,仅用于分类。

(7)Output predictions(输出预测):输出预测的评估数据,默认输出为Null(不输出),可选项有CSV、HTML、PlainText和XML。

注意: 在交叉验证的情况下,实例序号不对应于其在数据集中的位置。

(8)Cost-sensitive evaluation(代价敏感评估):将代价矩阵用于评估错误率。Set按钮允许用户指定所使用的代价矩阵。

(9)Random seed for XVal / % Split(XVal / %分割的随机种子):为了评估目的而划分数据之前,指定将数据进行随机化处理的随机种子。

(10)Preserve order for % Split(保持顺序按百分比分割):在将数据划分为训练集和测试集之前禁止随机化,即保持原来的顺序。

(11)Output source code(输出源代码):如果分类器能够输出所构建模型的Java源代码,可以在这里指定类名。可以在Classifier output(分类器输出)区域打印代码。

(12)Evaluation metrics(评价指标):设置评价指标,可选指标有Correct(正确率)、Incorrect(错误率)、Kappa(Kappa统计)、Total cost(总代价)、Average cost(平均代价)、KB relative(Kononenko & Bratko相关系数)、KB information(Kononenko & Bratko信息)、Correlation(相关性)、Complexity 0(复杂度0)、Complexity scheme(复杂度方案)、Complexity improvement(复杂度改进)、MAE(平均绝对误差)、RMSE(均方根误差)、RAE(相对绝对误差)、RRSE(相对均方根误差)、Coverage(覆盖度)、Region size(区域大小)、TP rate(真阳性率)、FP rate(假阳性率)、Precision(查准率)、Recall(查全率)、F-measure(F度量)、MCC(Matthews相关系数)、ROC area(接受者操作特征曲线下面积)和PRC area(查准率-查全率曲线下面积)。在Weka中,进行训练后的分类器模型将用于预测某个单一的类别属性,这就是预测的目标。一些分类器只能学习标称型类别的分类(分类问题),一些分类器只能学习数值型类别的分类(回归问题),还有一些分类器能学习两者。

默认情况下,数据集的最后一个属性是类别属性。如果想训练分类器来预测其他属性,可以单击Test options选项组下面的下拉列表框,选择其他属性作为类别属性。

2.3.2 分类器训练

设置好分类器、测试选项和类别属性后,单击Start按钮就启动学习过程。在Weka忙于训练分类器的同时,小鸟会站起来左右走动。用户随时可以单击Stop按钮终止训练过程。

训练结束后,右侧的Classifier output区域会显示训练和测试结果的文字描述,如图2.41所示。同时,在Result list(结果列表)区域中会出现一个新条目。后文再叙述结果列表,下面先仔细分析分类器输出的文字描述。

图2.41 分类器输出示例

2.3.3 分类器输出

拖动Classifier output区域右侧的滚动条,可以浏览全部结果文本。在文本区域中按住Alt键和Shift键的同时单击,会弹出一个对话框,可以以各种不同的格式(目前支持BMP、JPEG、PNG和EPS)保存所显示的输出。当然,也可以调整探索者界面的大小,得到更大的显示面积。输出分为以下几个部分。

(1)Run information(运行信息):提供处理过程所涉及的信息列表,如学习方案及选项(Scheme)、关系名(Relation)、实例(Instances)、属性(Attributes)和测试模式(Test mode)。

(2)Classifier model(full training set)(分类器模型(完整的训练集)):完整训练数据生成的分类模型的文字表述。本例选择J48决策树构建分类模型,因此以文字方式描述决策树。如果选择其他分类器模型,则显示相应的文字表述。

(3)根据所选择的测试模式,显示不同文字。例如,如果选择十折交叉验证,显示Stratified cross-validation;如果选择使用训练集,显示Classifier model(full training set),等等。由于评估内容较多,将结果分解显示如下。

① Summary(总结):一个统计列表,根据所选择的测试模式,总结分类器预测实例真实分类的准确度。具体项目如下。

● Correctly Classified Instances(正确分类的实例):显示正确分类的实例的绝对数量和百分比。

● Incorrectly Classified Instances(错误分类的实例):显示错误分类的实例的绝对数量和百分比。

● Kappa statistic(Kappa统计):显示Kappa统计量,[-1,1]范围的小数。Kappa统计指标用于评判分类器的分类结果与随机分类的差异度。K=1表明分类器完全与随机分类相异,K=0表明分类器与随机分类相同(即分类器没有效果),K=-1表明分类器比随机分类还要差。一般来说,Kappa统计指标的结果是与分类器的AUC指标以及准确率成正相关的,所以该值越接近1越好。

● Mean absolute error(平均绝对误差):显示平均绝对误差。

● Root mean squared error(均方根误差):显示均方根误差。

● Relative absolute error(相对绝对误差):显示相对绝对误差,百分数。

● Root relative squared error(相对均方根误差):显示相对均方根误差,百分数。

● Coverage of cases(0.95 level)(案例的覆盖度):显示案例的覆盖度,该值是分类器使用分类规则对全部实例的覆盖度,百分数越高说明该规则越有效。

● Mean rel. region size(0.95 level)(平均相对区域大小):显示平均相对区域大小,百分数。

● Total Number of Instances(实例总数):显示实例总数。

② Detailed Accuracy By Class(按类别的详细准确性):按每个类别分解的更详细的分类器的预测精确度。结果以表格形式输出,其中,表格列的含义如下。

● TP Rate(真阳性率):显示真阳性率,[0,1]范围的小数。

● FP Rate(假阳性率):显示假阳性率,[0,1]范围的小数。另外,常使用TN和FN分别代表真阴性率和假阴性率。

● Precision(查准率):显示查准率,[0,1]范围的小数。查准率用于衡量检索系统拒绝非相关信息的能力,计算公式为

● Recall(查全率):显示查全率,[0,1]范围的小数。查全率用于衡量检索系统检出相关信息的能力,计算公式为

● F-Measure(F度量):显示F度量值,[0,1]范围的小数。F度量是查准率和查全率的调和平均数,其计算公式为

● MCC(The Matthews Correlation Coefficient,Matthews相关系数):显示Matthews相关系数,[0,1]范围的小数。这是一个针对二元分类的有趣性能指标,特别是各个类别在数量上不平衡时。其计算公式为

● ROC Area(接受者操作特征曲线下面积):显示ROC面积,[0,1]范围的小数。ROC面积一般大于0.5,这个值越接近1,说明模型的分类效果越好。这个值在0.5~0.7时有较低准确度,在0.7~0.9时有一定准确度,在0.9以上时有较高准确度。如果该值等于0.5,说明分类方法完全不起作用,没有价值;而小于0.5的值不符合真实情况,在实际中极少出现。

● PRC Area(查准率-查全率曲线下面积):显示PRC面积,[0,1]范围的小数。

● Class(类别):显示类别标签。

表格前面几行按类别显示预测精确度,最后一行是各个类别的加权平均(Weighted Avg.)。

③ Confusion Matrix(混淆矩阵):显示每一个类别有多少个实例。矩阵元素显示测试的样本数,表行为实际的类别,表列为预测的类别。

④ Source code(optional)(源代码(可选)):如果用户在图2.40所示的Classifier evaluation options对话框中选中Output source code(输出源代码)复选框,在此位置将显示Java源代码。

前文提到过,一个分类器训练完成后,结果列表中就会出现一个条目,再训练一次,又会再出现一个条目。单击不同条目,可以来回切换显示各次训练的结果。按Delete键可以从结果中删除选定的条目。右击任意一个条目,会弹出一个快捷菜单,里面包含如下菜单项。

(1)View in main window(在主窗口中查看):在主窗口中显示输出,与单击该条目的功能相同。

(2)View in separate window(在单独的窗口中查看):打开一个新的独立窗口,查看结果。

(3)Save result buffer(保存结果缓冲区):弹出一个对话框,将文本输出保存为文本文件。

(4)Delete result buffer(删除结果缓冲区):删除训练结果。

(5)Load model(加载模型):从二进制文件中加载一个预先训练过的模型对象。

(6)Save model(保存模型):将模型对象保存为二进制文件,对象以Java序列化对象的格式保存。

(7)Re-evaluate model on current test set(重新在当前测试集上评估模型):使用在Supplied test set(提供测试集)选项下通过Set按钮设置的数据集,测试已构建好的模型的性能。

(8)Re-apply this model's configuration(重新应用本模型的设置)。

(9)Visualize classifier errors(可视化分类器错误):弹出一个可视化的窗口,将分类结果以散点图形式表示。正确分类的实例表示为小叉号,而错误分类的实例表示为小空心方块。

(10)Visualize tree or Visualize graph(可视化树或可视化图形):如果分类结果可以可视化,如决策树或贝叶斯网络,选择本菜单项会弹出一个分类器模型结构的图形化表示。如果已经构建了一个贝叶斯分类器,图形可视化选项就会出现。在树可视化工具中,可以右击空白区域带出快捷菜单,拖动鼠标可移动图形,单击某个节点可查看训练实例,按住Ctrl键的同时单击可缩小视图,按住Shift键的同时拖动一个方框可放大视图。图形可视化工具的使用很直观、友好。

(11)Visualize margin curve(可视化边缘曲线):生成散点图,说明预测边缘。将边缘定义为实际的分类预测概率与预测为其他类别的最高概率之间的差值。例如,通过增加训练数据的边缘,Boosting算法可以在测试数据上达到更好的性能。

(12)Visualize threshold curve(可视化阈值曲线):通过改变不同类别之间的阈值得到的预测,生成说明权衡(trade-offs)的散点图。例如,如果默认阈值为0.5,对于预测为“正”的实例,预测为“正”的概率必须大于0.5。该散点图可用于对查准率/查全率进行权衡的可视化,如ROC曲线分析(真阳性率vs假阳性率)和其他类型的曲线。

(13)Cost/Benefit analysis(代价/收益分析):对数据集属性的不同结果进行评价分析给出分析曲线,单击其中一项会给出分析曲线。

(14)Visualize cost curve(可视化代价曲线):产生散点图,给出一个明确表述的预期代价。

(15)Plugins(插件):当有可视化插件可供选择(默认值为无)时才会出现该菜单项。

2.3.4 分类算法介绍

分类和回归是数据挖掘和机器学习中极为重要的技术,其中分类是指利用已知的观测数据构建一个分类模型,常常称为分类器,来预测未知类别的对象的所属类别。分类和回归的不同点在于,分类的预测输出是离散型类别值,而回归的预测输出是连续型数值。因此,Weka将分类和回归都归为同一类算法。

本节介绍常用的分类算法,包括线性回归、决策树、决策规则、支持向量机,将贝叶斯网络和神经网络放到第6章讲解。由于Weka实现的分类算法数量众多,特点各异,无法在较短篇幅中讲清楚,读者可根据自己的需要查阅附录介绍和相关资料。

1.线性回归

线性回归(linear regression)是利用数理统计中的回归分析,来确定多个变量之间相互依赖的定量关系的一种统计分析方法,应用十分广泛。具体来说,它利用称为线性回归方程的最小二乘函数对一个或多个自变量(常表示为x)和一个标量型因变量(常表示为y)之间的关系进行建模,这种函数是一个或多个称为回归系数的模型参数的线性组合。只涉及一个自变量的称为简单线性回归,涉及多个自变量的称为多元线性回归。

线性回归的主要目标是用于预测。线性回归使用观测数据集的y值和x值来拟合一个预测模型,构建这样一个模型后,如果给出一个新的x值,但没有给出对应的y值,这时就可以用预测模型来预测y值。

给定p维数据集{xi1,…,xipyi}(i=1,2,…,N),线性回归模型假设因变量yi和自变量xi之间是线性关系,即

其中,假定xi0=1,将p维扩展为p+1维;粗体字表示向量;上标T表示矩阵转置;w是回归系数的向量;是向量w的内积。

p=1时,上式可简单表示为如下的一元线性回归的形式:

yi=w0+w1xi

其中,假定yi的方差为常数;回归系数w0w1对应直线在纵轴的截距和斜率,可以使用下列算式来估计:

其中,x1x2,…,xN的均值;y1y2,…,yN的均值。

通过N个数据点对回归方程进行拟合,估算出回归系数,就得到一条直线,通过这条直线就可以预测未知数据点的目标变量的值,如图2.42所示。

图2.42 一元线性回归

从第1章可以知道,CPU数据集就非常适合用线性回归进行处理。当拟合出回归公式之后,就可用于预测新测试实例的CPU性能。

2.决策树

决策树(decision tree)是一种预测模型,它包括决策节点、分支和叶节点三个部分。其中,决策节点代表一个测试,通常代表待分类样本的某个属性,在该属性上的不同测试结果代表一个分支,分支表示某个决策节点的不同取值。每个叶节点存放某个类别标签,表示一种可能的分类结果,括号内的数字表示到达该叶节点的实例数。

使用训练集用决策树算法进行训练,经过训练之后,学习方案只需要保存类似于图2.43所示的树形结构,而不像最近邻学习等消极学习算法那样,不保存模型,只有在需要分类时才去查找与测试样本最为相近的训练样本。决策树对未知样本的分类过程是,自决策树根节点开始,自上向下沿某个分支向下搜索,直到到达叶节点,叶节点的类别标签就是该未知样本的类别。

图2.43 决策树示例

对于如图2.43所示的决策树,假如有一个新的未知样本,属性值如下:

    outlook = rainy, temperature = cool, humidity = high, windy = FALSE

问是否能play?

按照决策树的分类过程,自根节点outlook开始,由于outlook=rainy,因此应该沿着最右边的分支向下搜索,下一个节点是windy,由于windy=FALSE,因此再次沿着最右边的分支向下搜索,遇到类别标签为yes的叶节点,因此推断未知样本的类别标签是yes,即可以play。

决策树算法通过将训练集划分为较纯的子集,以递归的方式建立决策树。有多种决策树算法,下面介绍使用广泛的C4.5和CART算法。

1)C4.5算法

C4.5算法是澳大利亚悉尼大学Ross Quinlan教授于1993年对早先的ID3算法进行改进而提出来的。C4.5算法在以下几个方面对ID3算法进行了改进。

(1)能够处理连续型属性和离散型属性的数据。

(2)能够处理具有缺失值的数据。

(3)使用信息增益率作为决策树的属性选择标准。

(4)对生成树修剪,降低过拟合。

C4.5算法可以使用通用的称为TreeGrowth的决策树归纳算法作为生长树算法。该算法的输入是训练集E和属性集F。算法递归地选择最佳属性以划分数据,并扩展树的叶节点,直到满足结束条件。算法的伪代码如算法2.1所示。

算法2.1 决策树归纳算法框架

    TreeGrowth(E, F)
      if stopping_cond(E, F) = true then
        leaf = createNode()
        leaf.label = Classify(E)
        return leaf
      else
        root = createNode()
        root.test_cond = find_best_split(E, F)
        令V = {v | v是root.test_cond 的一个可能的输出}
        for each vV do
          Ev={e | root.test_cond(e)=v and eE}
          child = TreeGrowth(Ev, F)
          添加child为root的子节点,并将边(root——>child)标记为v
        end for
      end if
      return root

算法所使用的函数如下。

(1)createNode()函数:为决策树创建新节点,以扩展决策树。决策树的节点要么有一个测试条件,记为node.test_cond;要么有一个类别标签,记为node.label。

(2)find_best_split()函数:确定应当选择哪个属性作为划分训练记录的测试条件。可以使用多种不纯性度量来评估划分,以选择测试条件。常用度量有信息熵和Gini指标等。

C4.5使用的度量称为信息增益率(GainRatio),是信息熵的变形。原来的算法直接使用信息熵的增益,会因某属性有较多类别取值因而导致有偏大的信息熵,从而更容易被选择为划分节点。信息增益率考虑了分裂信息的“代价”,能够部分抵消属性取值数量带来的影响,因此它是C4.5对ID3算法的重要改进之一。

(3)Classify()函数:确定叶节点的类别标签。对于每个叶节点t,令pi|t)表示该节点上属于类别i的训练记录所占的比例,在大多数情况下,将叶节点指派为具有多数记录的类别,即

其中,操作argmax返回最大化pi|t)的参数i

(4)stopping_cond()函数:通过检查是否所有的记录都属于同一个类别,或者都具有相同的属性值,决定是否终止决策树的增长。终止递归函数的另一种方式是,检查记录数是否小于某个最小阈值。

C4.5算法用到以下几个公式。

(1)信息熵:

其中,S为训练集;pii=1,2,…,m)为具有m个类别标签的类别属性C在所有样本中出现的频率。

(2)划分信息熵。

假设用属性A来划分S中的数据,计算属性A对集合S的划分熵值EntropyAS)。

如果A为离散型,有k个不同取值,则属性A依据这k个不同取值将S划分为k个子集{S1S2,…,Sk},属性A划分S的信息熵为

其中,|Si|和|S|分别为SiS中包含的样本个数。

如果属性A为连续型数据,则按属性A的取值递增排序,将每对相邻值的中点看作可能的分裂点,对每个可能的分裂点,计算

其中,SLSR分别对应于该分裂点划分的左右两部分子集。选择EntropyAS)值最小的分裂点作为属性A的最佳分裂点,并以该最佳分裂点按属性A对集合S的划分熵值作为属性A划分S的熵值。

(3)信息增益。

按属性A划分数据集S的信息增益Gain(SA)等于样本集S的熵减去按属性A划分S后的样本子集的熵:

Gain(SA)=Entropy(S)-EntropyAS

(4)分裂信息。

C4.5引入属性的分裂信息来调节信息增益:

(5)信息增益率:

信息增益率将分裂信息作为分母,属性取值数目越大,分裂信息值越大,从而部分抵消了属性取值数目所带来的影响。

下面以天气数据集(weather.nominal.arff文件)为例,演示C4.5算法构建决策树的过程。天气数据集内容可参见第1章。

第一步,计算所有属性划分数据集S所得的信息增益。

S为天气数据集,有14个样本。类别属性play有2个值{C1=yes,C2=no}。14个样本中,9个样本的类别标签取值为yes,5个样本的类别标签取值为no。即,C1=yes在S中出现的概率为9/14,C2=no出现的概率为5/14。因此S的熵为

下面计算按属性A划分S后的样本子集的信息熵。

首先看属性windy,它有2个可能的取值{false,true},将S划分为2个子集{S1S2},取值为false的样本子集S1共有8个样本,取值为true的样本子集S2共有6个样本。

对样本子集S1,play=yes有6个样本,play=no有2个样本,则

对样本子集S2,play=yes有3个样本,play=no有3个样本,则

利用属性windy划分S后的熵为

按属性windy划分数据集S所得的信息增益值为

Gain(S,windy)=Entropy(S)-EntropywindyS)=0.94-0.891=0.049

同理,得到S对其他所有属性的信息增益,列示如下:

Gain(S,outlook)=0.246

Gain(S,temperature)=0.029

Gain(S,humidity)=0.152

第二步,计算各个属性的分裂信息和信息增益率。

以outlook属性为例,取值为overcast的样本有4条,取值为rainy的样本有5条,取值为sunny的样本有5条,因此

同理,计算其他属性的信息增益率:

第三步,将信息增益率取值最大的那个属性作为分裂节点,因此最初选择outlook属性作为决策树的根节点,产生3个分支,如图2.44所示。

图2.44 选择第一个决策节点

第四步,对根决策节点的三个不同取值的分支,递归调用以上方法,求子树,最后得到的决策树如前面的图2.43所示。

C4.5算法还对生成树进行修剪,以克服过拟合。限于篇幅,就不展开来介绍了。

C4.5在Weka中的实现是J48决策树,后文将介绍J48的使用。

2)CART算法

CART(Classification and Regression Tree,分类及回归树)算法由美国斯坦福大学和加州大学伯克利分校的Breiman等人于1984年提出。CART决策树采用二元递归划分方法,能够处理连续型属性和标称型属性作为预测变量和目标变量下的分类。当输出变量为标称型属性数据时,所建立的决策树称为分类树,用于预测离散型标称类别。当输出变量为数值型变量时,所建立的决策树称为回归树,用于预测连续型数值类别。

CART算法同样使用算法2.1所示的决策树归纳算法框架,但与C4.5算法不同,CART为二叉分支,而C4.5可以为多叉分支;CART的输入变量和输出变量可以是分类型和数值型,而C4.5的输出变量只能是分类型;CART使用的不纯度量是Gini系数,而C4.5使用信息增益率;另外,两者对决策树的修剪方法不同。

CART算法使用Gini系数来度量对某个属性变量测试输出的两组取值的差异性,理想的分组应该尽量使两组中样本输出变量取值的差异性总和达到最小,即“纯度”最大,也就是使两组输出变量取值的差异性下降最快,“纯度”增加最快。

t为分类回归树中的某个节点,Gini系数计算公式为

其中,k为当前属性下测试输出的类别数;pj|t)为节点t中样本测试输出取类别j的概率。

t为一个节点,ξ为该节点的一个属性分支条件,该分支条件将节点t中的样本分别分到左分支SL和右分支SR中,称

为在分支条件ξ下节点t的差异性损失。其中,Gt)为划分前测试输出的Gini系数;|SR|和|SL|分别为划分后左右分支的样本个数。为使节点t尽可能纯,需选择某个属性分支条件ξ使该节点的差异性损失尽可能大。用ξt)表示所考虑的分支条件ξ的全体,则选择分支条件应为

对于CART分类树的属性选择,针对不同的属性类型(分类型和数值型),方法有所不同。对于分类型属性,由于CART只能建立二叉树,对于取多个值的属性变量,需要将多类别合并成两个类别,形成“超类”,然后计算两“超类”下样本测试输出取值的差异性;对于数值型属性,方法是将数据按升序排序,然后从小到大依次以相邻数值的中间值作为分隔,将样本分为两组,并计算所得组中样本测试输出取值的差异性。

CART算法使用的修剪方式是预修剪和后修剪相结合,而C4.5算法使用后修剪方式。

3.基于规则的分类器

基于规则的分类器是一种通过使用一组判断规则来对记录进行分类的技术。模型的规则使用析取范式R=(r1r2∨…∨rk),其中,规则ri的形式为ri:(Conditioni)→yi。规则左边称为规则前件(rule antecedent),是属性测试的合取;规则右边称为规则后件(rule consequent),包含预测类别yi

分类规则的质量可以用覆盖率(coverage)和准确率(accuracy)来度量。给定数据集D和分类规则r: Ay,规则的覆盖率定义为D中触发规则r的记录所占的比例,准确率定义为触发r的记录中列别标签等于y的记录所占的比例。

为了构建基于规则的分类器,需要提取一组规则来识别数据集属性和类别标签之间的关键联系。提取分类规则有两种方法:第一种是直接方法,直接从数据中提取分类规则;第二种是间接方法,从决策树等其他模型中进行提取。

规则提取的直接方法可以采用顺序覆盖(sequential covering)算法。算法的伪代码描述如算法2.2所示,算法开始时规则表R为空,函数Learn-One-Rule提取类别y覆盖当前训练记录集的最佳规则。在提取规则时,类别y的所有训练记录都视为正例,将其他类别的训练记录都视为反例。如果一个规则覆盖大多数正例,没有或仅覆盖极少数反例,那么该规则可取。一旦找到这样的规则,就删除它覆盖的训练记录,并把新规则追加到规则表R的尾部。重复这个过程,直到满足终止条件。然后,算法继续产生下一个类别的规则。

算法2.2 顺序覆盖算法

E为训练记录,A是属性-值对的集合
    设Y0为类别的有序集合{y1, y2, …, yk}
    设R={}为初始规则列表
    for 每个类别yY0-{yk} do
        while 终止条件不满足 do
            r←Learn-One-Rule(E, A, y)
            从E中删除r覆盖的训练记录
            追加r到规则列表尾部:RRr
        end while
    end for
    把默认规则{}→yk插入到规则列表R的尾部

规则提取的间接方法主要从决策树中提取规则。过程是,首先求出决策树,然后从每一个叶节点提取出来一个规则,再通过一些优化标准将可以合并的规则进行合并。

Weka提供多种基于规则的分类器。其中,JRip分类器实现了命题规则学习,重复增量修剪以减少产生错误(RIPPER),RIPPER是由William W. Cohen提出的一个优化版本的IREP。M5Rules分类器对于回归问题使用分治策略生成决策表。在每一次迭代中,使用M5并将“最好”叶子构成规则,以构建模型树。PART分类器使用分治方法产生PART决策表的类,在每次迭代中构建局部C4.5决策树,并将“最好”叶子构成规则。此外,还有ZeroR、OneR以及DecisionTable分类器。

4.基于实例的算法

基于决策树的分类框架包括两个步骤:第一步是归纳步,由训练数据构建分类模型;第二步是演绎步,将模型应用于测试样本。前文所述的决策树和基于规则的分类器都是先对训练数据进行学习,得到分类模型,然后对未知数据进行分类,这类方法通常称为积极学习器(eager learner)。与之相反的策略是推迟对训练数据的建模,直到需要对未知样本进行分类时才进行建模,采用这种策略的分类器称为消极学习器(lazy learner)。消极学习器的典型代表是最近邻方法,其途径是找出与测试样本相对接近的所有训练样本,这些训练样本称为最近邻(Nearest Neighbor,NN),然后使用最近邻的类别标签来确定测试样本的类别。

算法2.3是k-最近邻分类算法(简称kNN)的伪代码描述。对每一个测试样本z=(x'y'),计算该样本与所有训练样本(xy)∈D之间的距离dx'x),以确定其最近邻的集合DzD。显然,如果训练样本的数目很大,那么这种计算的开销会很大。

算法2.3 k-最近邻分类算法

一旦得到最近邻集合,测试样本就可以按照最近邻的多数类别进行分类,具体方法是进行多数表决,多数表决按如下公式计算:

其中,v为类别标签的所有可能取值;yi为某个最近邻的类别标签;I为指示函数,当参数为真时返回1,否则返回0。

以上的多数表决方法使用每个近邻对类别的影响都一样的方式,这使得算法对k的取值很敏感。降低k影响的一种方法是根据每个最近邻距离的不同对其影响加权,使靠近z的训练样本对分类的影响力大于那些远离z的训练样本。

Weka提供了多种消极学习器。其中,IBk分类器是一种k-最近邻分类器。IBk可用多种不同的搜索算法来加快寻找最近邻的任务,默认的搜索算法是线性搜索,但也可以使用其他算法,如kD-trees、Ball Trees以及称为Cover Trees(覆盖树)的算法。搜索方法使用距离函数作为参数,默认是欧氏距离,其他选项还有切比雪夫、曼哈顿和闵可夫斯基距离。最近邻数(默认k=1)可以用对象编辑器明确指定,或者使用留一法交叉验证来自动确定,但须指定值的上限。KStar分类器也是基于实例的分类器,其测试实例类以类似于它的训练实例类为基础,有一些类似的功能。它不同于其他基于实例的学习,因为它使用基于熵的距离函数。LWL分类器使用局部加权学习,它使用基于实例的算法分配实例权重,然后使用加权实例构建分类器。

5.支持向量机

支持向量机(Support Vector Machine,SVM)分类器是一种有监督学习的方法,广泛地应用于统计分类以及回归分析。SVM的特点是能够同时最小化经验误差与最大化几何边缘。因此,支持向量机也被称为最大边缘分类器。

支持向量机技术具有坚实的统计学理论基础,并在实践上有诸多成功示例。SVM可以很好地用于高维数据,避免维数灾难。它有一个独特的特点,就是使用训练实例的一个子集来表示决策边界,该子集称为支持向量,这就是其名称的来历。

数据分类是机器学习的一种常见任务。假定有一些给定的数据点,每个数据点属于两个类别之一,即二元分类,其分类目标是,确定一个新的数据点属于哪个类别。用支持向量机的观点,可以将一个数据点视为一个p维向量,问题就转换为是否可以使用一个(p-1)维超平面将这些点按类别进行分割,这就是所谓的线性分类器。有许多可能对数据进行分类的超平面,最佳的超平面应该是能够将两个类别最大限度地分离开来的超平面。所以选择的超平面应该能够将与两侧最接近的数据点的距离最大化。如果存在这样一个超平面,可称之为最大边缘超平面,所定义的线性分类器称为最大边缘分类器。如图2.45所示,超平面H1不能分割两个类别;超平面H2能够分割,但边缘很小;超平面H3能以最大边缘分割两个类别。

图2.45 超平面示意图来源:http://en.wikipedia.org/wiki/File:Svm_separating_hyperplanes_(SVG).svg。作者:ZackWeinberg。

支持向量机原先是为二元分类问题设计的,但它也可以扩展至能够处理多元分类问题。支持向量机分为线性支持向量机和非线性支持向量机,限于篇幅,本书只介绍线性支持向量机。

考虑一个包含N个训练样本的二元分类问题。设数据集为D,则

D={(xiyi)|xipyi∈{-1,1}} i=1,2,…,N

其中,yi的值为1或-1,表示点xi所属的类别;xip维的实数向量。目标是寻找一个能将yi=1和yi=-1的数据点进行分割的最大边缘超平面。任意超平面都可写为满足下式的点集:

w·x-b=0

其中,“·”代表点积;w代表超平面的法向量;参数决定超平面从原点沿法向量w的位移。

如果训练数据线性可分,可以选择两个超平面,使得它们能分割数据,且没有点落在两个超平面之间,然后尽量让两个超平面的距离最大化。这些超平面方程可以由下式描述:

w·x-b=1

w·x-b=-1

运用几何原理,可知两个超平面之间的距离为,因此最大化距离就是最小化,如图2.46所示。

图2.46 最大边缘超平面来源:http://en.wikipedia.org/wiki/File:Svm_max_sep_hyperplane_with_margin.png。作者:Peter Buch。

因为要阻止数据点落入边缘内,所以添加如下约束。

(1)对于属于第一个类别的xi,有w·xi-b≥1。

(2)对于属于第二个类别的xi,有w·xi-b≤-1。

上述两个公式可以合写为更紧凑的形式:对于全部的1≤iN,有yiw·xi-b)≥1。因此,线性支持向量机的最大化边缘等价于最小化如下的目标函数:

Weka提供多个支持向量机分类器算法。SMO分类器实现训练支持向量分类器的序列最小优化(Sequential Minimal Optimization,SMO)算法,使用诸如多项式或高斯核的核函数。Weka SMO分类器全局替换缺失值,将标称型属性转换为二元属性,默认情况下对属性进行规范化(输入标准化为零均值和单位方差),可关闭规范化选项。SMOreg分类器实现序列最小优化算法的学习支持向量回归模型。

6.集成学习

集成学习(ensemble learning)就是通过聚集多个分类器的预测结果来提高分类准确率。集成方法由训练数据构建一组基分类器(base classifier),然后通过每个基分类器的预测的投票来进行分类。一般来说,集成分类器的性能要好于任意的单个分类器,因为集体决策在全面可靠性和准确度上优于个体决策。

集成学习的逻辑视图如图2.47所示。其基本思想是,在原始数据上构建多个分类器,然后分别预测未知样本的类别,最后聚集预测结果。

图2.47 集成学习逻辑视图

构建集成分类器的方法有多种。使用最多的有如下两种。第一种处理训练数据集,根据某种决定某个样本抽取到的可能性大小的抽样分布,对原始数据进行二次抽样以得到多个训练集。然后,使用特定学习算法为每个训练集构建一个分类器。装袋(bagging)和提升(boosting)采用这种方法。第二种处理输入特征,通过选择输入特征的子集来得到多个训练集。这种方法特别适用于那些含有大量冗余特征的数据集。随机森林(random forest)采用这种方法。

集成学习的一般过程如算法2.4所示。集成学习对不稳定的分类器效果较好,不稳定的分类器对微小变化都很敏感,包括决策树、基于规则的分类器和人工神经网络。由于训练样本的可变性是分类器误差的主要来源之一,聚集在不同训练集上构建的基分类器,有助于减少这类误差。聚集方法一般是对单个预测值进行多数表决,也可以用基分类器的准确率对预测值进行加权,得到聚集后的预测结果。

算法2.4 集成学习的一般过程

D表示原始训练数据集,k表示基分类器的个数,T表示测试数据集
    for i = 1 to k doD创建训练集DiDi构建基分类器Ci
    end for
    for 每一个测试样本xT do
        C(x) = Vote(C1(x), C 2(x), …, Ck(x))
    end for

1)装袋

装袋又称为自助聚集(boot strap aggregation),是一种根据均匀概率分布从数据集中有放回重复抽样的技术。每个自助样本集都和原数据集一样大。由于抽样过程是有放回的,因此在同一个训练样本中可能会多次出现同一些样本,也可能有的不会出现。一般来说,自助样本Di大约包含原训练数据的63%,因为Di抽到一个样本的概率为1-(1-1/NN,如果N足够大,这个概率收敛于1-1/e≈0.632。装袋的过程如算法2.5所示,训练k个分类器后,分类器对单个预测值进行多数表决,将得票最高的类别指派给测试样本。

算法2.5 装袋算法

在算法中,指示函数IA)定义为,如果参数A为真,则IA)为1,否则为0。

装袋通过降低基分类器方差改善了泛化误差。装袋的性能依赖于基分类器的稳定性,装袋应该选择不稳定的基分类器,这样有助于降低因训练数据的随机波动导致的误差。由于选中每个样本的概率都相同,因此装袋并不偏重于原训练数据集中的任何样本,不太受过拟合的影响。

2)提升

提升是一个自适应改变训练样本分布的迭代过程,使基分类器重点关注那些难以分类的样本。不像装袋,提升为每一个训练样本赋一个权重,在每一轮提升过程结束时可以自动调整权重。赋值给训练样本的权重可用于以下两个方面。

第一,用作抽样分布,从原始数据集中抽取自助样本集合。

第二,可以为基分类器所用,学习偏向于高权重样本的模型。

因此,提升算法就是利用样本的权重来确定训练集的抽样分布。开始时所有样本的权重都等于1/N,抽样到的概率都一样,抽样得到新样本集后经过训练得到一个分类器,并用它来对原始数据集中的所有样本进行分类。每一轮提升都增加错误分类样本的权重,减小正确分类样本的权重,这使得分类器在后续迭代中关注那些难以分类的样本。

已经有多种提升算法的实现,其主要差别是:第一,每轮提升后更新样本权重的算法不同;第二,汇集各个分类器的预测结果的方法不同。其中,AdaBoost算法使用广泛,因此本书介绍AdaBoost算法,其基分类器的重要性依赖于它的分类错误率。错误率定义为

其中,xj为第j个样本;Cixj)为第i个分类器对样本xj的分类结果;I为指示函数(如果参数A为true,则IA)=1,否则为0);wj为权重。

基分类器Ci的重要性按下式计算:

如果错误率接近0,则αi为正无穷;如果错误率接近1,则αi为负无穷。

参数αi用于更新训练样本权重,AdaBoost权重更新机制由下式决定:

其中,Zj为规范化因子,用于确保

AdaBoost算法不使用多数表决的方案,而是对分类器Ci的预测值根据αi加权。这样,有助于惩罚那些准确率很低的模型。另外,如果某一轮产生大于50%的误差,则将权重重新恢复为初始值,重新抽样,重做该轮的提升。AdaBoost算法伪代码如算法2.6所示。

算法2.6 AdaBoost算法

Weka的实现算法为AdaBoostM1,它使用AdaBoost算法的M1方法,提升标称型类别的分类器类。M1方法只能处理标称型分类的问题,通常会显著提高性能,但有时会过拟合。Weka AdaBoostM1的实现代码与上面的算法稍有不同,如果第i轮中的错误率εi>0.5或者εi=0,就设置τ为1(只使用一个基分类器,不启用集成学习)并退出。另外,Weka还提供LogitBoost,它使用以回归方法为基础的学习,能处理多元分类问题。

3)随机森林

随机森林是一类专门为决策树分类器设计的集成学习方法。它集成多棵决策树的预测,其中每棵树都是基于随机向量的一个独立集合的值产生的。

通过随机森林得到基分类器Ci的算法主要分为如下两步。

第一步,对给定原始训练集采用有放回的自助取样,得到和原始训练集大小一致的训练集,与装袋方法一致。

第二步,随机选取分裂属性集。假设共有M个属性,指定一个小于M的属性数F,在整个森林的生长过程中,F的值一般维持不变。每棵树任其生长,即充分生长,不进行修剪。在每个内部节点,从M个属性中随机抽取F个属性作为分裂属性集,以最好的分裂方式对节点进行分裂。

随机森林的组合输出采用简单多数投票法(针对分类)得到,或者采用多棵决策树输出结果的简单平均值(针对回归)得到。

Weka提供实现随机森林的RandomForest算法。

2.3.5 分类模型评估

1.定性评估标准

一般来说,分类模型有如下评估标准。

(1)预测的准确率:模型正确地预测新的或先前没见过的样本的类别标签能力。

(2)速度:产生和使用模型的计算开销。

(3)强壮性:对于有噪声或具有缺失值的样本,模型能正确预测的能力。

(4)可伸缩性:给定很大的数据集,能有效地构造模型的能力。

(5)可解释性:学习模型提供的理解和解释的层次。

预测的准确率常用于比较和评估分类器的性能,它将每个类别看成同等重要,因此可能不适合用来分析不平衡数据集。在不平衡数据集中,稀有类别比多数类别更有意义。也就是说,需要考虑错误决策、错误分类的代价问题。例如,在银行贷款决策中,贷款给违规者的代价远远比由于拒绝贷款给不违规者而造成生意损失的代价大得多;在诊断问题中,将实际没有问题的机器误诊为有问题而产生的代价比因没有诊断出问题而导致机器损坏而产生的代价小得多。

对于一个二元分类问题,预测可能产生四种不同的结果,如表2.1所示。真阳性(True Positive,TP)和真阴性(True Negative,TN)都是正确分类结果,即预测类别和真实类别相符。假阳性(False Positive,FP)发生在当预测类别为yes而真实类别为no时,假阴性(False Negative,FN)发生在当预测类别为no而真实类别为yes时。

表2.1 二元预测的不同结果

通常可以将表2.1推广至多元分类的问题,只不过增加一些行和列,称为二维混淆矩阵,常用来展示对测试集的预测结果。真实类别对应矩阵行,预测类别对应矩阵列,矩阵单元则显示对应的测试样本数目。也有文献将真实类别对应矩阵列,预测类别对应矩阵行,只是将行列对调,并没有实质的区别。好的测试结果应该是主对角线上的数值要大,而其他非主对角线上单元的数值要小。

2.常用度量

对于二元分类问题,有如下的简单度量标准。

真阳性率(True Positive Rate,TPR)等于TP除以真实类别为yes的总数(TP+FN),即

真阴性率(True Negative Rate,TNR)等于TN除以真实类别为no的总数(FP+TN),即

假阳性率(False Positive Rate,FPR)等于FP除以真实类别为no的总数(FP+TN),即

假阴性率(False Negative Rate,FNR)等于FN除以真实类别为yes的总数(TP+FN),即

综合准确率等于正确分类总数除以全体分类总数。知道这些“率”之后,对应的错误率则是1减去这些率。

另外,查全率(Recall)和查准率(Precision)是两个使用广泛的度量,其定义为

查准率确定分类器断定为正例的那部分记录中实际为正例的记录所占的比例。查准率越高,分类器的假阳性率就越低。查全率度量分类器正确预测的正例的比例,如果分类器的查全率高,则很少将正例误分为负例。实际上,查全率的值等于真阳性率。

分类算法的主要任务之一就是构建一个最大化查全率和查准率的模型。可以将查全率和查准率合并成一个称为F1的度量,Weka称F1为F-Measure。

F1表示查全率和查准率的调和均值。可以把上式改写为

由于两个数的调和均值趋向于接近较小的值,因此F1度量值高可以确保查全率和查准率都比较高。

3.接受者操作特征曲线

接受者操作特征(Receiver Operating Characteristic,ROC)曲线是显示分类器真阳性率和假阳性率之间折中的一种图形化方法。在ROC曲线中,x轴为假阳性率,y轴为真阳性率,曲线的每个点对应某个分类器归纳的模型,如图2.48所示。

图2.48 ROC曲线

ROC曲线有几个关键点,公认的解释如下。

● (FPR=0,TPR=0):把每个实例都预测为负例的模型。

● (FPR=1,TPR=1):把每个实例都预测为正例的模型。

● (FPR=0,TPR=1):理想模型。

好的分类模型应该尽可能靠近ROC图的左上角,随机猜测的模型应位于连接点(FPR=0,TPR=0)和点(FPR=1,TPR=1)的主对角线上。

ROC曲线下面积(Area Under the Curve,AUC)提供了另一种评估模型的平均性能的方法。如果模型是完美的,则它的ROC曲线下面积等于1;如果模型是随机猜测的,则它的ROC曲线下面积等于0.5;如果一个模型比另一个模型好,则它的ROC曲线下面积较大。

2.3.6 手把手教你用

1.使用C4.5分类器

本例使用C4.5分类器对天气数据集进行分类。

首先加载天气数据集,操作步骤为:启动探索者界面,在Preprocess标签页中单击Open file按钮,选择并打开data目录中的weather.nominal.arff文件;然后,切换到Classify标签页。

从前面的学习中可以知道,构建决策树的C4.5算法在Weka中是作为一个分类器来实现的,名称为J48。单击Classify标签页上部的Choose按钮,打开分类器分层列表。单击trees条目以展开其子条目,然后单击J48条目选择该分类器。与过滤器一样,分类器也按层次进行组织,J48的全名为weka.classifiers.trees.J48。

在Choose按钮旁边的文本框内,可以看到当前分类器及选项:J48 -C 0.25 -M 2。这是此分类器默认的参数设置,对于J48分类器,一般不用更改这些参数就可以获得良好的性能。

为了便于说明,下面使用训练数据进行性能评估。使用训练数据进行评估并不是一个好方法,因为它会导致盲目乐观的性能估计。如同期末试题就从平时测验中抽取一样,绝大部分学生都能考得很好,但这并不意味着他们都掌握了课程知识。在Classify标签页的Test options(测试选项)选项组中,选中Use training set(使用训练集)单选按钮,以确定测试策略。做好上述准备之后,可以单击Start(开始)按钮,启动分类器的构建和评估,使用当前选择的学习算法J48,通过训练集构建J48分类器模型。然后,使用构建的模型对训练数据的所有实例进行分类以评估性能,并输出性能统计信息,如图2.49所示。

图2.49 选择测试选项

训练和测试结果会以文本方式显示在探索者界面右侧的Classifier Output(分类器输出)区域中。读者可拖动右边的滚动条以检查这些文字信息。首先看决策树的描述部分,其信息重新摘录如图2.50所示。

图2.50 决策树的文字描述

图2.50中的文字表示构建的J48修剪(pruned)决策树,包括决策节点、分支和叶节点。决策节点用一个测试表示,分支用“|”加上缩进表示,叶节点后面有一个括号,括号内的数字代表到达该叶节点的实例数量。当然,采用文字对模型进行表述十分笨拙且难以理解,因此Weka也能生成等效的图形表示。

按照上述方法,如果更改数据集或调整选项,每次单击Start按钮,都会构建和评估一个新的分类器模型,在图2.49所示窗口左下角的Result list(结果列表)区域中就会相应添加一个新条目。

可以按照如下方法得到图形化表示的决策树。右击刚刚被添加到结果列表中的trees.J48条目,并在弹出的快捷菜单中选择Visualize tree(可视化树)菜单项,会弹出如图2.51所示的决策树视图窗口。该决策树视图可以自动缩放和平移,可以通过选择右击空白处而弹出的快捷菜单中的Auto Scale菜单项实现视图的自动缩放,可以通过按下鼠标左键并拖动鼠标实现视图平移。

图2.51 构建的决策树

可见,图2.51与图2.50表示的信息是一致的。其中,叶节点中用括号括起的数字表示到达该节点的实例数量。另外,图2.50中的文字描述还包含两条额外信息:Number of Leaves(叶子数量)表示叶节点的数量,Size of the tree(树大小)表示树中全部节点的数量。

现在来看看分类器输出的其余信息。输出中接下来的两个部分给出了基于选定的测试选项得到的分类模型的质量报告。第一部分是一段文字描述:

    Correctly Classified Instances           14      100%

这段文字描述了正确分类的测试实例有多少条,占多大比例。它表示使用数据测试模型的准确性。本例中,准确性高达100%,表示完全正确。不用惊奇,这是使用训练集进行测试时经常发生的事。

分类器输出的最后一项是一个如下所示的混淆矩阵:

    === Confusion Matrix ===
     a  b   <-- classified as
     9  0 | a = yes
     0  5 | b = no

矩阵中的每一个元素都是实例的计数值。行表示真实类别,列表示预测类别。可以看到,全部9个真实类别为yes的实例都已预测为yes,全部5个真实类别为no的实例都已预测为no。只有主对角线上的数值很大,而非主对角线上的数值都为0,表明预测完全正确。

以上是使用训练集作为测试策略得到的训练结果,当然,还可以选择使用其他的测试策略。单击Start按钮启动所选学习算法的运行,使用Preprocess标签页中加载的数据集和所选择的测试策略。例如,如果使用十折交叉验证,需要运行十次学习算法,以构建和评估十个分类器。要注意的是,打印到分类器输出区域的分类器模型是由完整的训练集构建的,这是最后一次运行学习算法得到的结果。

现在加载iris数据集,还是使用J48分类器进行学习。首先选择使用Use training set测试选项,然后选择使用Cross-validation十折测试选项,分别训练并评估J48分类器,运行结果如表2.2所示。

表2.2 两种测试选项的运行结果

测试选项 释义 正确分类的测试实例 正确分类比例
Use training set 使用训练集 147 98%
Cross-validation(10 folds) 交叉验证(十折) 144 96%

从表2.2中的数据可以看到,使用训练集的正确分类所占的比例较高,达到98%。但由于是直接将训练集用于测试,因此结论并不可靠。相反,十折交叉验证将数据集分为十等份,将其中的一份用于测试,另外九份用于训练,如此依次进行十次训练和评估,显然得到的结论要可靠一些。

最后,检查一下分类器错误的可视化表示。右击结果列表中的trees.J48条目,从弹出的快捷菜单中选择Visualize classifier errors(可视化分类器错误)菜单项,会弹出一个散点图窗口,正确分类的实例标记为小叉号,不正确分类的实例标记为小空心方块,如图2.52所示。

图2.52 可视化分类器错误散点图

图2.52中,横坐标表示真实类别,纵坐标表示预测类别。注意,不要为表面现象迷惑,一个小叉号并不一定只代表一个实例,一个小空心方块有时也并不仅仅代表一个错分的实例。如果想看到底有几个错分实例,可以拉动Jitter滑块,此时会错开一些相互叠加的实例,便于看清楚到底有多少个错分的实例。另一种办法是单击小空心方块,此时会弹出如图2.53所示的实例信息,显示每个实例的各属性值以及预测类别和真实类别。

图2.53 实例信息

2.使用分类器预测未知数据

还是使用J48分类器对天气数据集进行训练,得到如图2.51所示的决策树。

现在构建一个测试数据集,用任意的文本编辑器,编辑如下内容:

    @relation weather.symbolic
    @attribute outlook {sunny, overcast, rainy}
    @attribute temperature {hot, mild, cool}
    @attribute humidity {high, normal}
    @attribute windy {TRUE, FALSE}
    @attribute play {yes, no}
    @data
    rainy, cool, high, FALSE, yes

将测试数据集保存为weather.nominal.test.arff文件。

然后,在Classify标签页的Test options选项组中,选择Supplied test set作为测试策略,单击后面的Set按钮,打开Test Instances(测试实例)窗口,如图2.54所示。单击窗口中的Open file按钮,打开刚才保存的测试数据集weather.nominal.test.arff文件,单击Close按钮关闭窗口。

图2.54 Test Instances窗口

接着,单击Test options选项组下部的More options按钮,打开如图2.55所示的Classifier evaluation options(分类器评估选项)对话框,单击对话框中部的Choose按钮,选择PlainText选项,该选项使分类器的输出中包含预测信息,单击OK按钮关闭对话框。

图2.55 Classifier evaluation options对话框

现在,一切准备都已就绪。单击Start按钮启动分类器训练和评估过程,像以前那样,Weka会在分类器输出区域输出性能统计信息。仔细查看,会发现多了如下一项对测试集的预测结果,表明测试集仅有一个实例,预测值和实际值都为yes,预测没有错误。

    === Predictions on test set ===
     inst#    actual predicted error prediction
        1    1:yes    1:yes     1

3.使用决策规则

本示例使用决策规则训练天气数据集,并评估分类器性能。

首先启动探索者界面,在Preprocess标签页中加载weather.nominal.arff数据文件。切换至Classify标签页,单击Choose按钮,选择rules条目下的JRip分类器,保持默认参数不变。单击Start按钮启动训练,训练结果如图2.56所示。

图2.56 JRip分类器训练结果

经过训练,生成的规则一共有如下三条:

    JRIP rules:
    ===========
    (humidity = high) and (outlook = sunny) => play=no (3.0/0.0)
    (outlook = rainy) and (windy = TRUE) => play=no (2.0/0.0)
     => play=yes (9.0/0.0)
    Number of Rules : 3

每条规则用“=>”分开规则前件和规则后件,规则后件中有用括号括起的两个数字,第一个数字表示规则覆盖的实例数量,第二个数字表示错分的实例数量。注意到第三条规则的规则前件为空,表示这条规则覆盖除去前两条规则覆盖的训练实例外的所有实例。

同样也可以可视化分类器错误。右击结果列表中的rules.JRip条目,从弹出的快捷菜单中选择Visualize classifier errors菜单项,会弹出一个散点图窗口,在窗口中拉动Jitter滑块,会错开一些相互叠加的实例,如图2.57所示。在分类器错误散点图中,左上角和右下角的小方块都是错误分类的实例,左下角的小蓝叉和右上角的小红叉都是正确分类的实例。可以直观地看到一共有五个错分实例。

图2.57 可视化JRip分类器错误散点图

4.使用线性回归

本示例使用线性回归训练CPU数据集,并评估分类器性能。

首先启动探索者界面,在Preprocess标签页中加载cpu.arff数据文件。如图2.58所示,在界面右下角可以看到第一个属性MYCT的直方图,由于类别属性是连续型数值,因此该直方图不是彩色的。

图2.58 加载CPU数据集

切换至Classify标签页,单击Choose按钮,选择functions条目下的LinearRegression分类器,保持默认参数不变,单击Start按钮启动训练,训练结果如图2.59所示。

图2.59 LinearRegression训练结果

从结果中可以看到,LinearRegression分类器构建了一个回归公式,交叉验证得到的各项误差指标显示其性能不佳。

再次单击Choose按钮,选择另一种分类器M5P,该分类器在trees条目下。还是保持默认参数不变,单击Start按钮启动训练,训练结果如图2.60所示。

图2.60 M5P训练结果

从图2.60中可以看到,M5P是决策树方案和线性回归方案的结合体。前半部分使用修剪的决策树,后半部分则使用线性回归。如果要稍微深入了解M5P算法的原理,不妨在结果列表中右击trees.M5P条目,在弹出的快捷菜单中选择Visualize tree菜单项,Weka弹出如图2.61所示的决策树的可视化结果。修剪模型树,使用数据集中六个属性中的三个进行分叉,树根对CHMIN属性分叉,在左分支上得到一个线性模型LM1,剩余的结构放到右分支上,继续分叉,得到另外的四个线性模型LM2~LM5。一共有五个叶节点,每个叶节点对应一个线性模型。括号中有两个数字:第一个数字表示达到该叶节点的实例数量;第二个百分数表示用该叶节点的线性模型对这些实例进行预测的均方根误差,用百分比表示对全部训练数据计算而得到的类别属性的标准偏差。

图2.61 M5P树

为了对两个分类器的性能有一个直观的认识,下面使用可视化方法来观察两个学习方案的误差。在Result list区域中分别右击两个条目,在弹出的快捷菜单中选择Visualize classifier errors菜单项,得到两个学习方案的可视化误差如图2.62和图2.63所示。显示的数据点随类别属性值的不同而异,由于类别属性是连续型数值,因此数据点的颜色也是连续变化的。这里选择MMAX属性作为X轴,CACH属性作为Y轴,这样数据点能够尽量散开。每个数据点用一个叉号表示,其大小表示该实例的误差的绝对值。可以看到,图2.63中的叉号数量多于图2.62中的叉号数量,说明M5P的性能优于LinearRegression。当然,如果觉得从图上看起来眼花缭乱,不妨只从分类器输出的误差指标上来看,例如,LinearRegression的平均绝对误差(MAE)为41.0886,M5P的平均绝对误差(MAE)为29.8309,从其他指标的比较也可以看出M5P的性能较好。

图2.62 LinearRegression误差

图2.63 M5P误差

5.使用用户分类器

用户分类器(User Classifier)允许Weka用户以交互方式建立自己的分类器。该分类器位于分层列表中的trees条目之下,名称为UserClassifier,全名为weka.classifiers.trees.UserClassifier。如果在自己的Weka版本中找不到该分类器,说明还没有安装,请按照第1章中Weka包管理器的相关内容进行安装。

本例使用segment数据集来说明操作方式。根据给定的平均intensity(亮度)、hue(色调)、size(大小)、position(位置),以及各种简单的纹理特征的属性,将视觉图像数据分割成各种分类标签,如grass(草)、sky(天空)、foliage(树叶)、brick(砖)和cement(水泥)。训练数据文件随Weka软件配附,名称为segment-challenge.arff。加载该数据文件,选择UserClassifier分类器。

图2.64 Test Instances窗口

评估使用特殊的测试集,名为segment-test.arff,在Classify标签页的Test options选项组中选中Supplied test set(提供测试集)单选按钮。这里要注意,用户分类器不能使用交叉验证进行评估,因为无法为每个折都手动构建分类器。单击Supplied test set单选按钮后面的Set按钮,弹出Test Instances(测试实例)窗口,如图2.64所示。单击Open file按钮,选择data目录下的segmenttest.arff文件,再单击Close按钮关闭Test Instances窗口。

然后,单击Classify标签页中的Start按钮,启动交互构建分类器的界面。这时,探索者界面右下角的小鸟站起来不断走动,表明Weka正在等待用户完成分类器的构建工作。

弹出的窗口中包括Tree Visualizer(树可视化工具)和Data Visualizer(数据可视化工具)两个标签页,可以切换不同的视图。前者显示分类树的当前状态,并且每个节点都给出到达该节点的每个类别的实例数目。构建用户分类器的目标就是得到一棵叶节点尽可能纯净的树。最初只有一个根节点,其中包含全部数据。可以切换到Data Visualizer标签页去创建分割,其中显示了一个二维散点图。可以参考2.7.1节中介绍的Visualize标签页的使用方法,选择一个属性作为X轴,另一个属性作为Y轴。这里的目标是要找到一个X轴和Y轴的属性组合,将不同类别尽可能完全进行分离。尝试多遍以后,读者可能会找到一个好的选择:使用region-centroid-row属性作为X轴,使用intensity-mean属性作为Y轴,这样会将红色的实例(位于散点图左上方)几乎完全与其他实例分离,如图2.65所示。

图2.65 数据可视化工具

找到了很好的分离点之后,必须在图中指定一个区域。在Jitter滑块上方的下拉列表框中可以选择四种选择工具,选择Select Instance(选择实例)选项,可标识一个特定实例;选择Rectangle(矩形)选项,可在图形上拖出一个矩形;选择Polygon(多边形)选项,可绘制一个自由形状的多边形;选择Polyline(折线)选项,可绘制一条自由形状的折线。其操作方式都是:单击添加一个顶点,右击完成操作。一旦选择某个区域,该区域会变成灰色。在图2.65中,用户已经定义好了一个矩形。如果单击Submit(提交)按钮,则会在树中创建两个新的节点,一个节点容纳选定的实例,另一个节点容纳其余的实例。Clear(清除)按钮用于清除选择,Save(保存)按钮用于将当前树的节点实例保存为一个ARFF文件。

这时,Tree Visualizer标签页中显示如图2.66所示的树。左边的节点表示sky类别,纯粹只有一种类别,但右边的节点还是混合了多个分类,需要进一步进行分割。单击不同节点,可以在Data Visualizer标签页中切换显示不同的数据子集。继续添加节点,直到得到满意的结果,也就是说,直到叶节点大多是只有一种分类的纯节点为止。然后,在Tree Visualizer标签页的任意空白处右击,并在弹出的快捷菜单中选择Accept the Tree(接受树)菜单项。Weka使用测试集评估建立的树,并输出性能统计信息。对于本例,90%已经是很高的得分了。

图2.66 树可视化工具

这是非常考验细心和耐心的工作,如果能得到93%以上的成绩是很值得骄傲的。

现在和Weka的机器学习比试一下。还是使用同样的训练集和测试集,但选择J48分类器来替换用户分类器,单击Start按钮启动训练和评估。本例J48分类器的正确率高达96.1728%,的确是手工交互进行分类难以达到的目标。

6.使用支持向量机

本实践分为两个部分,第一部分展示如何使用SMO分类器,第二部分展示如何使用LibSVM。

启动探索者界面,首先在Preprocess标签页中加载iris数据集,然后切换至Classify标签页,单击Classifier选项组中的Choose按钮,选择functions条目下的SMO分类器,使用默认的十折交叉验证测试选项,单击Start按钮启动分类模型构建并评估,运行结果如图2.67所示。

图2.67 SMO运行结果

本例使用指数为1的PolyKernel(多项式核),使得模型成为线性支持向量机。由于iris数据包含三个类别值,就输出三个对应的二元SMO模型,这是因为一个超平面能分隔任意两个可能的类别值。此外,由于SVM是线性的,超平面表示为在原来空间中的属性值的函数,参见图2.67中的函数表达式。

图2.68所示为将多项式核函数的指数(exponent)选项设置为2的结果,这使得支持向量机成为非线性的。和前面一样,也有三个二元的SMO模型,但这次超平面表示为支持向量的函数。支持向量显示在尖括号中,还显示其系数α的值。在每个函数的最后,显示偏移量参数β的值(等同于α0),参见图2.68中的函数表达式。

图2.68 指数设置为2的结果

图2.69所示为两次实验的混淆矩阵。比较后容易得出,两次实验使用的是不同的多项式核,使得支持向量机一个为线性,另一个为非线性,但对于本例来说,尽管错分的实例不同,但两者错分的实例数都是6个。

图2.69 两次实验的混淆矩阵

LibSVM是中国台湾的林智仁(Chih-Jen Lin)教授于2001年开发的一套支持向量机的库,网址为http://www.csie.ntu.edu.tw/~cjlin/libsvm/。该库的运算速度非常快并且开源,支持Java、C#、.Net、Python、Matlab等多种语言,因此非常受用户欢迎。

Weka 3.7.2以后的版本都直接支持LibSVM,包装LibSVM的工作由Yasser ELManzalawy完成,网址为http://weka.wikispaces.com/LibSVM。最重要的类就是包装LibSVM工具的包装类——LibSVM,由于使用LibSVM构建SVM分类器,因此它的运行比SMO快得多。并且LibSVM可以支持One-class SVM、Regressing SVM以及nu-SVM。

下面简单说明实验步骤。如果没有安装LibSVM,请关闭包括探索者在内的Weka图形用户界面,然后按照第1章中介绍的包管理器的相关内容安装LibSVM,当前LibSVM包的版本为1.0.3。接着启动探索者界面,加载iris数据集,选择LibSVM分类器,并单击Start按钮运行,结果如图2.70所示。可以看到,LibSVM错分的实例数仅有5个,比SMO性能稍好。

图2.70 LibSVM运行结果

7.使用元学习器

元学习器能将简单的分类器变为更加强大的学习器,这里以实例进行说明。

首先加载鸢尾花数据集,然后选择DecisionStump分类器,这是一个被称为决策树桩的简单分类器,全名为weka.classifiers.trees.DecisionStump。接着选择十折交叉验证为测试选项进行训练和评估,得到的分类正确率为66.6667%。

图2.71 AdaboostM1分类器选项

接下来,选择AdaBoostM1分类器,这是一个使用提升算法的集成学习器,其全名为weka.classifiers.meta.AdaBoostM1。单击该分类器进行配置,出现如图2.71所示的对象编辑器对话框。为了和DecisionStump分类器进行比较,设置AdaBoostM1的基分类器为DecisionStump分类器。如果需要,还可以继续单击以进一步配置基分类器的选项,但由于DecisionStump没有属性需要设置,因此可单击OK按钮返回到Classify标签页,并单击Start按钮启动训练。

图2.71中的numIterations参数默认为10,即表示训练会迭代提升DecisionStump分类器10次。图2.72所示的运行结果表明,在150个iris数据中,只有7个错分的实例,分类正确率高达95.3333%。

图2.72 AdaboostM1分类器运行结果

考虑到DecisionStump算法本来就十分原始,并且只经过很少次数的迭代提升,可知其性能提高很大,令人满意。

8.深入研究离散化

本示例研究离散化的效果。加载ionosphere.arff数据文件构建J48决策树,该数据集包含从电离层传回的雷达信号信息。数据集共有34个属性外加1个类别属性,共有351个实例,没有缺失值。二元类别标签分别是good和bad,其中,good的样本指那些能够显示出电离层中的一些结构类型证据的实例,而bad的样本指信号直接穿过电离层的实例。更为详细的信息可以查看ARFF文件中的注释。

首先以无监督离散化开始,采用十折交叉验证,比较不同学习方案的正确率以及决策树的大小。采用J48分类器对原始数据进行分类,正确分类的实例数量为321,正确率为91.453%,叶节点数为18,树的大小为35;然后使用无监督的Discretize过滤器,保持过滤器参数为默认值,先进行过滤,再采用J48分类器对过滤后的数据进行分类,正确分类的实例数量为304,正确率为86.6097%,叶节点数为46,树的大小为51;最后将无监督Discretize过滤器的makeBinary参数设置为True,其余参数仍为缺省值,先进行过滤,再采用J48分类器对过滤后的数据进行分类,正确分类的实例数量为326,正确率为92.8775%,叶节点数为9,树的大小为17。无监督离散化的效果如表2.3所示。

表2.3 无监督离散化效果

研究表2.3的结果,可以得出这样的结论:使用二元化的无监督离散化,可以提高分类器的正确率,并大幅减少决策树的大小。

现在轮到有监督离散化。这里出现一个微妙的问题,如果简单地重复使用有监督离散化方法替换无监督离散化,结果必然过于乐观。因为这里将交叉验证用于评价,测试集里的数据在确定离散间隔时已经使用过,必然造成如同预先偷看到答案再考试的效果。对于新的数据,这就无法给出一个合理的性能评估。

要合理地评估有监督离散化,最好使用Weka的元学习器FilteredClassifier。它仅使用训练数据来构建过滤器,然后,使用训练数据计算得到的离散间隔来离散化测试数据,并予以评估。总之,这种方式完全符合在真实实践中处理新数据的过程。

仍然使用ionosphere.arff数据文件,取消在Preprocess标签页中选择的过滤器,并在Classify标签页中选择FilteredClassifier分类器,其全名为weka.classifiers.meta.FilteredClassifier。设置该分类器的classifier为J48,filter为有监督的Discretize,保持默认参数不变,如图2.73所示。

图2.73 设置FilteredClassifier分类器

这时,单击Start按钮启动训练及评估,得到输出结果:正确分类的实例数量为320,正确率为91.1681%,叶节点数为21,树的大小为27。然后,修改FilteredClassifier分类器的filter参数,将有监督Discretize的makeBinary参数设置为True,其余参数仍为缺省值,filter文本框中的命令行应该是Discretize -D -R first-last。再次单击Start按钮,得到输出结果:正确分类的实例数量为325,正确率为92.5926%,叶节点数为9,数的大小为17。有监督离散化的效果如表2.4所示。

表2.4 有监督离散化效果

仍然可以得出这样的结论:使用二元化的有监督离散化,可以提高分类器的正确率,并大幅减少决策树的大小。

9.初识最近邻分类器

本示例使用IBk分类器,这是一种k-最近邻分类器,既可以在交叉验证的基础上选择合适的k值,也可以对实例加距离权重。可选的距离加权方法有如下三种:No distance weighting(默认)、Weight by 1/distance和Weight by 1-distance。

在探索者界面中加载glass.arff数据集,切换至Classify标签页,单击Choose按钮选择IBk分类器,其全名为weka.classifiers.lazy.IBk。使用交叉验证测试该分类器的性能,使用交叉验证并保持折数为默认值10。IBk的选项都保持为默认值,这里要注意的参数是KNN,KNN值默认为1,这是分类时所用的近邻实例的数量。

单击Start按钮运行一次分类算法,记录正确分类的百分比,其值为70.5607%。然后,修改KNN值为5,再次运行分类算法,记录正确分类的百分比,其值为67.757%,如图2.74所示。

图2.74 IBk分类器

可见,将KNN参数值由1增大至5后,IBk的准确度稍微有所下降。从这个示例中,读者可能会凭直觉得出KNN值越小越好的结论,事实真是这样吗?且看后文。

10.分类噪声与最近邻学习

和其他技术一样,最近邻学习对训练数据中的噪声很敏感。本示例将大小不等的分类噪声注入数据中,并观察其对分类器性能的影响。

本示例使用一种称为AddNoise的无监督的属性过滤器来添加噪声,该属性过滤器位于weka.filters.unsupervised.attribute包中,使用该过滤器,可以将数据中一定比例的类别标签翻转为随机选择的其他值。然而,对于本次实验,最重要的是要保证测试数据不受分类噪声的影响,这样才能得到可靠的评估结果。很多实际情况都要求过滤训练数据,但不能过滤测试数据,满足这种要求的元学习器称为FilteredClassifier,位于weka.classifiers.meta包中。本例将该元学习器配置为使用IBk作为分类器,使用AddNoise作为过滤器。在运行学习算法之前,FilteredClassifier先对数据应用过滤器进行过滤,分两批完成:先过滤训练数据,后过滤测试数据。AddNoise过滤器只在遇到的首批数据中添加噪声,也就是说,随后的测试数据在通过时不受任何影响。

还是使用玻璃数据集,在Classify标签页中选择FilteredClassifier分类器,然后打开通用对象编辑器编辑该分类器的参数,设置classifier为IBk,filter为AddNoise,如图2.75所示。

图2.75 FilteredClassifier分类器参数

修改IBk分类器的邻居数量KNN参数,分别设置为k=1、k=3、k=5。同时修改AddNoise过滤器的分类噪声百分比percent参数,从0%、10%一直到100%。每次设置完毕后,单击Start按钮启动训练和评估,将得到的分类正确率填入表2.5中。

表2.5 不同近邻数量及噪声对IBk的影响

表2.5供读者自行完成。为了便于说明问题,在表2.6中列出答案,并在图2.76中画出对应的折线图。

表2.6 不同近邻数量及噪声对IBk的影响答案

图2.76 不同近邻数量及噪声对IBk的影响折线图

在图2.76所示的折线图中,横坐标为噪声,纵坐标为分类准确率。对折线图进行分析,容易得到如下结论。

第一,当噪声增大时,分类准确率随之下降。

第二,改变k值,对分类准确率的影响较为复杂。总体来说,增大k值会抑制噪声,增加分类准确率;但k值过大,且分类噪声百分比较小(约低于20%)时,会降低分类准确率。

上述结论告诉我们,由于数据集或多或少都会受到噪声干扰,最近邻学习需要找到一个合适的k值,既能抑制噪声干扰,又不显著降低分类准确率。

11.研究改变训练集大小的影响

本示例讨论学习曲线,显示训练数据量逐渐增加后的效果。同样使用玻璃数据集,但这一次使用IBk以及在Weka中的实现为J48的C4.5决策树学习器。

获取学习曲线,再次使用FilteredClassifier分类器,这一次结合Resample(其全称为weka.filters.unsupervised.instance.Resample)过滤器,其功能是抽取出给定的一定比例的数据集,返回减少后的数据集。与上一个示例相同,只为第一批训练数据应用过滤器,所以测试数据在通过FilteredClassifier分类器到达分类器之前,并不会受任何修改。

具体步骤是,首先加载玻璃数据集,然后选择FilteredClassifier分类器,打开通用对象编辑器编辑该分类器的参数,分别设置classifier为IBk和J48,filter为Resample,如图2.77所示。

图2.77 FilteredClassifier分类器参数

设置classifier为IBk(k=1)或J48,同时修改Resample过滤器的子样本大小百分比sampleSizePercent参数,从10%一直到100%。每次设置完毕后,单击Start按钮启动训练和评估,将得到的分类正确率填入表2.7中。

表2.7 改变训练集大小对IBk和J48的影响

表2.7供读者自行完成。为了便于说明,在表2.8中列出答案,并在图2.78中画出对应的折线图。

表2.8 改变训练集大小对IBk和J48的影响答案

图2.78 改变训练集大小的影响折线图

在图2.78中,横坐标为训练集大小,纵坐标为分类准确率。容易从中得到以下结论。

第一,当增大训练数据量时,分类准确率随之增加。

第二,相对于IBk,增大训练数据量对J48的影响更为显著。