WEKA 十折交叉验证结果不一致
Incosistency of results in ten-fold cross validation in WEKA
昨天在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)
方法二:每次折叠使用方法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 文档,以上两种方式应该有相同的结果,即方式 2 的平均结果(例如,精度,召回率)应该等于方式 1 的结果.但事实是它们不一样,谁能找出我代码中的错误,或者提供其他好的评估方法?谢谢大家!
Way1是Weka GUI中广泛使用的基本方法,所以crossValidationModel()
可以得到与Weka Explorer相同的平均结果,喜欢下面的操作
1.Open Weka 软件
2.Enter Explorer 模块
3.Choose 预处理 选项卡中的数据集
4.Choose J48 和 10-fold 在 Classify 中的交叉验证选项卡
5.Click 开始按钮获取结果分类器输出 window
Way2是另一种方法,我们可以得到每个折叠的结果。每次折叠的结果与Weka Experimenter中的结果相同,如下操作
打开Weka软件
进入Experimenter模块
单击新建按钮在设置选项卡[=12=中新建一个简单实验]
在 Results Destination、Datasets 和 Algorithms 中设置参数
点击运行选项卡中的开始按钮,每次折叠的结果保存在[=]定义的文件中43=]结果目标
总而言之,这2种方法肯定是return2个不同的结果,根据给出的源代码是其办公网站https://weka.wikispaces.com/Generating+cross-validation+folds+(Java+approach),以上方法应该得到一致的结果,但事实恰恰相反,这可能是Weka的bug。
如果您查看 weka.classifiers.Evaluation.crossValidateModel
方法的代码(取决于您的版本,委托对象),您会发现它使用了 weka.core.Instances.trainCV(int,int,Random)
方法。此外,您需要使用完整数据集的 class 先验来初始化 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)
昨天在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)
方法二:每次折叠使用方法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 文档,以上两种方式应该有相同的结果,即方式 2 的平均结果(例如,精度,召回率)应该等于方式 1 的结果.但事实是它们不一样,谁能找出我代码中的错误,或者提供其他好的评估方法?谢谢大家!
Way1是Weka GUI中广泛使用的基本方法,所以crossValidationModel()
可以得到与Weka Explorer相同的平均结果,喜欢下面的操作
1.Open Weka 软件
2.Enter Explorer 模块
3.Choose 预处理 选项卡中的数据集
4.Choose J48 和 10-fold 在 Classify 中的交叉验证选项卡
5.Click 开始按钮获取结果分类器输出 window
Way2是另一种方法,我们可以得到每个折叠的结果。每次折叠的结果与Weka Experimenter中的结果相同,如下操作
打开Weka软件
进入Experimenter模块
单击新建按钮在设置选项卡[=12=中新建一个简单实验]
在 Results Destination、Datasets 和 Algorithms 中设置参数
点击运行选项卡中的开始按钮,每次折叠的结果保存在[=]定义的文件中43=]结果目标
总而言之,这2种方法肯定是return2个不同的结果,根据给出的源代码是其办公网站https://weka.wikispaces.com/Generating+cross-validation+folds+(Java+approach),以上方法应该得到一致的结果,但事实恰恰相反,这可能是Weka的bug。
如果您查看 weka.classifiers.Evaluation.crossValidateModel
方法的代码(取决于您的版本,委托对象),您会发现它使用了 weka.core.Instances.trainCV(int,int,Random)
方法。此外,您需要使用完整数据集的 class 先验来初始化 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)