【问题标题】:Incosistency of results in ten-fold cross validation in WEKAWEKA 中十倍交叉验证的结果不一致
【发布时间】:2018-12-01 21:43:12
【问题描述】:

昨天我在weka中用2种方式实现了10折交叉验证,但是结果不一致。

方式一:直接调用方法eval.crossValidateModel()

 J48 j48 = new J48();
 j48.buildClassifier(ins);  // ins is the Instances object
 Evaluation eval = new Evaluation(ins);
 eval.crossValidateModel(j48, ins, 10, new Random(1)); // 10-fold cross validation
 ... // get results by eval.getXX(0) or eval.getXXX(1)

方式2:在每个折叠中使用方法testCV()trainCV()

 ins.randomize(new Random(1)); // ins is the Instances object
 ins.stratify(10); // randomize the dataset then split into 10 folds

 for(int i=0; i<10; i++){       
    Instances trainData = ins.trainCV(10, i);
    Instances testData = ins.testCV(10, i);
    J48 j48 = new J48();
    j48.buildClassifier(trainData);

    Evaluation eval = new Evaluation(trainData);
    eval.evaluateModel(j48, testData);
    ... // get results by eval.getXX(0) or eval.getXXX(1)
 }

根据weka api docs,上述2种方式应该有相同的结果,即方式2的平均结果(例如,精度,召回)应该等于方式1的结果。但事实是它们不一样,任何人都可以找出我代码中的错误,或者提供其他不错的评估方法吗?谢谢大家!

【问题讨论】:

标签: weka cross-validation


【解决方案1】:

如果您查看weka.classifiers.Evaluation.crossValidateModel 方法的代码(取决于您的版本,委托对象),您会发现它使用了weka.core.Instances.trainCV(int,int,Random) 方法。此外,您需要使用完整数据集的类先验来初始化Evaluation 对象。

这是更新后的代码:

Evaluation eval = new Evaluation(ins);  // init evaluation
rand = new Random(1);
int numFolds = 10;  // 10-fold CV
ins.randomize(rand); // randomize the data
ins.stratify(numFolds); // stratify the randomized data for 10-fold CV
J48 template = new J48();  // classifier template for evaluation
//template.setOptions(...);  // if further options need to be set

for (int i = 0; i < numFolds; i++) {       
  Instances trainData = ins.trainCV(numFolds, i, rand);
  Instances testData = ins.testCV(numFolds, i);
  Classifier cls = AbstractClassifier.makeCopy(template);  // copy of classifier template
  cls.buildClassifier(trainData);
  eval.evaluateModel(cls, testData);  // accumulate statistics
}

... // get results by eval.getXX(0) or eval.getXXX(1)

【讨论】:

  • 是的,crossValidateModel()的源代码在调用trainCV(int,int,Random)时确实使用了随机种子,但我尝试使用trainCV(int,int,Random),但结果也超出了的结果方式1。另一个问题是我们需要用trainData而不是ins来初始化Evaluation对象。
  • 根据我的试验,WAY 1WAY 2的结果与Explorer中使用Weka GUI得到的结果一致Experimenter 模块。我注意到Weka论坛上有很多相关的问题,这是Weka的错误吗?
  • Experimenter 和 Explorer 处理交叉验证的方式不同。 Explorer 将一个交叉验证运行的结果组合在一个评估对象中(如命令行)。实验者将每个折叠对视为单独的评估。这就是为什么 Experimenter 可以计算 mean/stdev 而 Explorer 不能。
  • 我认为你是对的,但是官方的使用示例并没有在每个折叠中使用trainCV()方法中的随机种子,请参阅CrossValidationSingleRun.java。另一个问题,为什么你使用makecopy() 方法而不是实例化一个J48 对象?
  • 这是我多年前写的一个老例子(当时我更多地参与了 Weka 项目)。两者之间发生了变化。无论如何,我们目前正在移动 wiki。将在那里更新代码。使用了makeCopy 方法,因此您只需配置一次分类器。例如,如果您执行交叉验证以获取统计数据,然后在完整数据集上构建最终模型以进行部署。每次只需使用 makeCopy 方法创建模板的副本(您只需在一个地方更改设置)。
【解决方案2】:

Way1 是 Weka GUI 中广泛使用的基本方法,因此crossValidationModel() 可以与 Weka Explorer 给出相同的平均结果,例如以下操作.

1.打开Weka软件

2.进入Explorer模块

3.在预处理选项卡中选择数据集

4.在分类选项卡中选择J4810-fold交叉验证

5.点击开始按钮,在分类器输出窗口

中获取结果

Way2 是一种替代方法,我们可以得到每个折叠的结果。每次折叠的结果与Weka Experimenter中的结果相同,如下操作。

  1. 打开Weka软件

  2. 进入Experimenter模块

  3. 单击新建按钮在设置选项卡

  4. 中新建一个简单实验
  5. Results DestinationDatasetsAlgorithms

  6. 中设置参数
  7. 点击运行选项卡中的开始按钮,每次折叠的结果都保存在Results Destination

  8. 中定义的文件中

总而言之,这2个方法肯定会返回2个不同的结果,根据其办公网站https://weka.wikispaces.com/Generating+cross-validation+folds+(Java+approach)给出的源代码,上述方法应该得到一致的结果,但事实恰恰相反,也许这是Weka 的一个 bug。

【讨论】:

    猜你喜欢
    • 2013-02-21
    • 2014-09-13
    • 2023-03-10
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 2019-07-27
    • 2012-12-14
    相关资源
    最近更新 更多