如何解决WEKA调用evaluateModel时的NullPointerException错误?
问题:Weka调用evaluateModel时出现NullPointerException错误
现象
- 交叉验证
crossValidateModel可正常执行,但调用evaluateModel时抛出空指针异常 - 更换测试集或改用J48分类器仍出现相同错误
- 数据集无缺失值,由Matlab双精度数组转换生成,包含198个特征+1个类别属性,共3600个数值型实例
错误堆栈
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "weka.filters.unsupervised.attribute.ReplaceMissingValues.input(weka.core.Instance)" because "this.m_Missing" is null at weka.classifiers.functions.SMO.distributionForInstance(SMO.java:1443) at weka.classifiers.evaluation.Evaluation.evaluationForSingleInstance(Evaluation.java:2208) at weka.classifiers.evaluation.Evaluation.evaluateModelOnceAndRecordPrediction(Evaluation.java:2246) at weka.classifiers.evaluation.Evaluation.evaluateModel(Evaluation.java:2122) at weka.classifiers.Evaluation.evaluateModel(Evaluation.java:689) at ClassCleanSMO.main(ClassCleanSMO.java:78)
完整代码
import weka.core.Instances; import weka.core.converters.ArffLoader; import weka.filters.unsupervised.attribute.NumericToNominal; import weka.filters.unsupervised.attribute.ClassAssigner; import weka.filters.supervised.attribute.PartitionMembership; import weka.filters.supervised.instance.ClassBalancer; import weka.classifiers.Evaluation; import java.util.Random; import weka.classifiers.functions.SMO; public class ClassCleanSMO { public static void main(String[] args) throws Exception{ // Loader ArffLoader loader = new weka.core.converters.ArffLoader(); loader.setFile(new java.io.File("C:/Users/redmello/Desktop/traininput2.arff")); Instances ClassData= loader.getDataSet(); // FILTERS // Nun2Nominal NumericToNominal N2N = new weka.filters.unsupervised.attribute.NumericToNominal(); N2N.setInputFormat(ClassData); String[] options = new String[2]; options[0] = "-R"; options[1] = "last"; N2N.setOptions(options); ClassData = weka.filters.Filter.useFilter(ClassData, N2N); // ClassAssigner ClassAssigner MyClass= new weka.filters.unsupervised.attribute.ClassAssigner(); MyClass.setInputFormat(ClassData); String[] options3 = new String[2]; options3[0] = "-C"; options3[1] = "last"; MyClass.setOptions(options3); ClassData = weka.filters.Filter.useFilter(ClassData, MyClass); // PartitionMembership PartitionMembership PartMemb = new weka.filters.supervised.attribute.PartitionMembership(); PartMemb.setInputFormat(ClassData); ClassData = weka.filters.Filter.useFilter(ClassData, PartMemb); // ClassBalancer ClassBalancer ClassBal = new weka.filters.supervised.instance.ClassBalancer(); ClassBal.setInputFormat(ClassData); String[] options4 = new String[1]; options4[0] = "10"; ClassBal.setOptions(options4); ClassData = weka.filters.Filter.useFilter(ClassData, ClassBal); // DATA MINING // crossValidationFoldMaker + J48 Evaluation eval = new Evaluation(ClassData); SMO svm = new SMO(); eval.crossValidateModel(svm, ClassData, 10, new Random(1)); System.out.println(eval.toSummaryString("\nResults\n\n",false)); eval.evaluateModel(svm,ClassData); } }
解决建议
- 根本原因:
crossValidateModel内部会创建分类器的副本进行训练,不会修改你定义的svm对象——这个原始SMO实例从未被训练过,内部的m_Missing过滤器未初始化,调用evaluateModel时触发空指针。 - 方案1:显式训练模型后再评估
修改代码,在调用evaluateModel前先执行训练:// 先训练SMO模型 svm.buildClassifier(ClassData); // 再执行评估 eval.evaluateModel(svm, ClassData); - 方案2:若无需额外评估,可直接使用交叉验证输出的结果,删除
eval.evaluateModel(svm,ClassData)这一行 - 额外检查:确认
PartitionMembership和ClassBalancer的参数设置是否符合数据集需求,避免数据结构异常引发后续问题
内容的提问来源于stack exchange,提问作者Emiliano Rosso
相关产品推荐
相关产品推荐

