/DataMining2

2019春季班数据挖掘编程作业2

Primary LanguageJava

数据挖掘实验3

姓名:崔子寒 学号:161220026 Email: cuizihan@nju.edu.cn

一、提交说明

本次实验提交文件分为三个部分,包括训练测试结果、可执行jar包和完整工程。其中训练测试结果是调用weka的API,使用不同的分类方法,对所有数据进行十折交叉验证得到的结果。可执行jar包可以在命令行下执行java -jar来运行,复现实验结果。完整工程是完整的工程代码,使用maven作为构建工具。

二、实验过程

1. 实验思路

本次实验提供的文件格式是arff文件,这是weka工具包使用的数据的文件格式,因此使用weka工具包提供的机器学习算法进行训练。本次实验需要比较:

  • J48决策树算法
  • 朴素贝叶斯(Naive Bayes) 算法
  • 支持向量机(SVM)算法
  • 神经网络(Neural Network)
  • K近邻(KNN)算法

以及这些算法的使用Bagging集成学习在给定的10个arff数据文件上的表现。weka提供了GUI界面,可以直接在界面上选中文件和所用的算法进行学习,不过对于10个文件和总共10个分类器来说,要进行100次操作,是比较低效的。所以编写程序,调用weka提供的API,自动的完成上述过程,并将结果输出至文件。

2. 代码设计

2.1 添加依赖

maven项目比较容易添加weka依赖,在pom.xml中添加如下的依赖:

<!-- https://mvnrepository.com/artifact/nz.ac.waikato.cms.weka/weka-stable -->
    <dependency>
      <groupId>nz.ac.waikato.cms.weka</groupId>
      <artifactId>weka-stable</artifactId>
      <version>3.8.0</version>
    </dependency>

之后就可以调用weka的API进行机器学习。

2.2 程序设计

weka通过Instances类来加载arff文件,Instances类有一个单参数构造器,需要传入一个java.io.Reader对象,t通过Reader,Instances类导入arff文件信息。

通过阅读weka源码可以发现,所有的基分类器都实现了classifier接口,这个接口的定义如下:

public interface Classifier {
    void buildClassifier(Instances var1) throws Exception;
    double classifyInstance(Instance var1) throws Exception;
    double[] distributionForInstance(Instance var1) throws Exception;
    Capabilities getCapabilities();
}

这个接口有两个方法buildClassifierclassifyInstance,从字面意思理解,分别用来训练和测试。

如果要进行集成学习,weka.classifier.meta下提供了一些集成学习算法。以Bagging为例,Bagging继承了抽象类SingleClassifierEnhancer,这个抽象类有下面这个方法:

public void setClassifier(Classifier newClassifier) {
        this.m_Classifier = newClassifier;
    }

所以我们创建了集成学习器后,调用setClassifier来设置基学习器,之后就可以进行训练了。

如果要进行十折交叉验证,可以使用weka.classifiers.Evaluation类,这个类的部分定义如下:

public class Evaluation implements Serializable, Summarizable, RevisionHandler {
   ...
    public void crossValidateModel(Classifier classifier, Instances data, int numFolds, Random random, Object...){...}
                                   
    public String toSummaryString() {...}

    public String toClassDetailsString(){...}
    ...

我们主要用到三个方法:crossValidateModel方法需要传入的参数有:一个Classifier接口、数据集、交叉验证的折数和随机数种子。通过设定numFolds = 10,就可以进行十折交叉验证。toSummaryString将返回交叉验证的总体结果,包括正确分类数目,准确度。toClassDetailsString返回更多的性能度量标准,包括TPR,FPR,Precision,Recall等指标。

因此,大致的思路如下:

  1. 首先加载所有的arff文件,将它们名称存储在一个List <String> L1中。
  2. 创建所有的分类器对象,将它们储存在一个List<Classifier> L2中。
  3. 两层循环,先从L2中取出一个分类器,然后在L1中的所有数据上分别进行十折交叉验证,输出结果。
 for(MyClassifier classifier : classifiers) {
 	for(String file : files) {
 		MyEvaluation.tenCrossValidate(classifier,file);
 		...
 	}
 }

三、 测试结果

1. 程序运行

程序运行后,会在控制台输出每个分类器训练测试所用的总时长,输出的格式如下:

运行结果

并将每个分类器的表现输入至result目录下的文件中:

log

2 性能度量

经过统计,得到每一个分类器和对应的集成分类器在每个文件上的表现,得到下表:

J48 贝叶斯 SVM 神经网络 KNN
Acc(%) ROC Acc(%) ROC Acc(%) ROC Acc(%) ROC Acc(%) ROC
breast-w 普通 94.56 0.955 95.99 0.988 97.00 0.968 95.28 0.986 95.14 0.973
集成 96.28 0.985 95.85 0.991 97.00 0.975 95.99 0.989 95.85 0.987
colic 普通 85.33 0.813 77.99 0.842 82.61 0.809 80.43 0.857 81.25 0.802
集成 85.59 0.864 77.99 0.842 83.97 0.868 84.51 0.876 81.25 0.824
credit-a 普通 86.09 0.887 77.68 0.896 84.93 0.856 83.62 0.895 81.16 0.808
集成 86.81 0.928 77.83 0.896 85.22 0.888 85.07 0.908 81.30 0.886
credit-g 普通 70.50 0.639 75.40 0.787 75.10 0.671 71.50 0.730 72.00 0.660
集成 73.30 0.753 74.80 0.787 75.40 0.754 76.10 0.776 72.10 0.694
diabetes 普通 73.83 0.751 76.30 0.819 77.34 0.720 75.39 0.793 70.18 0.650
集成 74.60 0.798 76.56 0.817 77.47 0.747 76.82 0.822 71.09 0.725
hapatitis 普通 83.87 0.708 84.52 0.860 85.16 0.756 80.00 0.823 80.64 0.653
集成 83.87 0.865 85.81 0.890 85.81 0.828 84.52 0.846 81.29 0.782
mozilla4 普通 94.80 0.954 68.64 0.829 83.21 0.838 91.19 0.940 88.99 0.877
集成 95.11 0.976 68.74 0.830 83.12 0.849 91.28 0.945 88.86 0.928
pc1 普通 93.33 0.668 89.18 0.650 92.97 0.500 93.60 0.723 92.06 0.74
集成 93.60 0.855 88.91 0.628 93.15 0.512 93.33 0.833 91.07 0.793
pc5 普通 97.46 0.817 96.42 0.830 97.17 0.541 97.10 0.941 97.29 0.932
集成 97.53 0.959 96.48 0.842 97.18 0.572 97.31 0.954 97.37 0.953
waveform-5000 普通 75.08 0.813 80.00 0.941 86.68 0.918 83.56 0.954 73.62 0.779
集成 81.20 0.936 79.98 0.941 86.26 0.944 85.68 0.962 74.46 0.880

计算每个分类器在所有数据集上的平均准确率,以及它们的集成训练的平均准确率,得到下表:

J48 贝叶斯 SVM 神经网络 KNN
平均ACC 85.49 82.21 86.22 85.17 83.23
平均ACC(集成) 86.79 82.29 86.46 87.06 83.46
平均提升 1.30 0.08 0.24 1.89 0.23

可视化数据:

acc

3. 时间代价

在十折交叉验证的过程中,记录了每一个分类器一级它们的集成的时间消耗,数据如下表:

J48 贝叶斯 SVM 神经网络 KNN
普通集成 普通集成 普通集成 普通集成 普通集成
用时(分钟) 0.2 1.6 0.02 0.2 1.15 11.23 24.83 261.2 1.1 10.2

可视化数据:

time

4. 实验结论

综合性能度量和时间代价,可以得到如下的结论:

  • 复杂的分类器例如神经网络,SVM在面对不同的数据集时都有较好的性能,而简单的分类器如:贝叶斯,决策树,KNN在某些数据上表现较好,但是在某些数据集上表现不好。
  • 集成学习可以有效提高分类器的性能。
  • 集成学习应该遵循"好而不同"的原则,选择基分类器时既应该考虑基分类器的性能,也应该考虑多个基分类器会不会效果相似,从而无法达到集成学习的目的。从结果来看,使用决策树和神经网络作为基分类器效果较好,而一些简单的分类器如朴素贝叶斯,KNN则不会带来性能的显著提升。
  • 简单的学习器训练速度快,而复杂的学习器训练速度很慢。所以在可以接受性能略低的情况下,可以选择决策树这样的分类器。

四、 优化Bagging KNN

1. 关于Bagging

Bagging是直接基于自助采样法的集成学习方法,通过有放回的随机采样,可以得到T个含m个样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基学习器进行结合。对于分类任务,采用简单投票法;对于回归任务,采用简单平均法。

从偏差-方差分解的角度看,Bagging关注降低方差,所以在决策树、神经网络等容易受样本扰动的学习器上的效果更为明显。

2. 调优

Weka中的Bagging集成学习有如下的参数:

参数名类型描述
bagSizePercent int Size of each bag, as a percentage of the training set size.
calcOutOfBag boolean Whether the out-of-bag error is calculated.
classifier Classifier The base classifier to be used.
numIterations int The number of iterations to be performed.
seed int The random number seed to be used.

基学习器我们指定为KNN,可以供调整的参数有bagSizePercentcalOutOfBagnumIterationsseed. 其中seed仅用于随机抽样,和性能关系不大,所以探究bagSizePercentcalOutOfBagnumIterations这三个参数和性能的关系。

以colic.arff的数据为例,通过调整参数得到准确率随着参数变化的数据

calOutOfBag bagSizePercent numIterations
True 10 15 20 25
100 81.25% 81.52% 81.52% 81.25%
False bagSizePercent 10 15 20 25
70 80.71% 80.52% 80.43% 80.98%
80 80.98% 80.98% 80.71% 81.25%
90 81.25% 81.25% 80.98% 80.71%
100 80.71% 81.25% 81.25% 80.98%

可以看出在使用包外误差进行辅助计算,并且适当调整包的个数是可以带来性能提升的。当使用包外误差,包的个数为15个时,达到了81.52%,比默认参数提高了0.6个百分点。接着我们固定Bagging的参数,对KNN的参数进行调整。

KNN的主要参数包括近邻的个数K,距离度量函数,通过调整这两个参数得到如下数据:

距离度量函数K
1 2 3 4 5
欧式距离 81.52% 81.52% 82.01% 82.88% 82.34%
曼哈顿距离 80.43% 83.15% 83.42% 81.52% 82.34%
![knn](https://github.com/czhnju161220026/image/blob/master/knn.png?raw=true)

在尝试不同的K和距离度量函数后,发现使用曼哈顿距离,K=3时正确率最高,为83.42%,较默认参数提升了2.6个百分点。

因此,可以总结出提升Bagging KNN的一些方法:

  • 使用包外误差进行辅助计算
  • 调整Bag的个数,确定一个比较好的基分类器数目
  • 多尝试一些度量函数和近邻个数K

五、 实验总结和参考

这次实验学到了关于Weka工具包的用法,锻炼了自己的编程能力和数据分析能力,获益匪浅。

参考: