Java,weka LibSVM 没有正确预测

Java, weka LibSVM does not predict correctly

我在 java 代码中使用 LibSVM 和 weka。我正在尝试进行回归。下面是我的代码,

public static void predict() {

    try {
        DataSource sourcePref1 = new DataSource("train_pref2new.arff");
        Instances trainData = sourcePref1.getDataSet();

        DataSource sourcePref2 = new DataSource("testDatanew.arff");
        Instances testData = sourcePref2.getDataSet();

        if (trainData.classIndex() == -1) {
            trainData.setClassIndex(trainData.numAttributes() - 2);
        }

        if (testData.classIndex() == -1) {
            testData.setClassIndex(testData.numAttributes() - 2);
        }

        LibSVM svm1 = new LibSVM();

        String options = ("-S 3 -K 2 -D 3 -G 1000.0 -R 0.0 -N 0.5 -M 40.0 -C 1.0 -E 0.001 -P 0.1");
        String[] optionsArray = options.split(" ");
        svm1.setOptions(optionsArray);

        svm1.buildClassifier(trainData);

        for (int i = 0; i < testData.numInstances(); i++) {

            double pref1 = svm1.classifyInstance(testData.instance(i));                
            System.out.println("predicted value : " + pref1);

        }

    } catch (Exception ex) {
        Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
    }
}

但是我从此代码得到的预测值与我使用 Weka GUI 得到的预测值不同。

示例: 下面是我为 java 代码和 weka GUI 提供的单个测试数据。

Java 代码预测值为 1.9064516129032265,而 Weka GUI 的预测值为 10.043。我对 Java 代码和 Weka GUI 使用相同的训练数据集和相同的参数。

我希望你理解我的 question.Could 谁能告诉我我的代码有什么问题?

您使用了错误的算法来执行 SVM 回归。 LibSVM 用于分类。你想要的是SMOreg,这是一个特定的回归支持向量机。

下面是一个完整的示例,展示了如何使用 Weka Explorer GUI 和 Java API 来使用 SMOreg。对于数据,我将使用 Weka 发行版附带的 cpu.arff 数据文件。请注意,我将使用此文件进行训练和测试,但理想情况下您会有单独的数据集。

使用 Weka Explorer GUI

  1. 打开 WEKA 资源管理器 GUI,单击 Preprocess 选项卡,单击 Open File,然后打开应该在您的 Weka 发行版中的 cpu.arff 文件。在我的系统上,该文件位于 weka-3-8-1/data/cpu.arff 下。资源管理器 window 应如下所示:

  1. 单击 Classify 选项卡。它真的应该叫 "Prediction" 因为你可以在这里做分类和回归。在 Classifier 下,点击 Choose 然后 select weka --> classifiers --> functions --> SMOreg ,如下图。

  1. 现在构建回归模型并对其进行评估。在 Test Options 下选择 Use training set 以便我们的训练集也用于测试(正如我上面提到的,这不是理想的方法)。现在按 Start,结果应如下所示:

记下 RMSE 值 (74.5996)。我们将在 Java 代码实现中重新讨论它。

使用JavaAPI

下面是一个完整的 Java 程序,它使用 Weka API 来复制之前在 Weka Explorer GUI 中显示的结果。

import weka.classifiers.functions.SMOreg;
import weka.classifiers.Evaluation;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ConverterUtils.DataSource;

public class Tester {

    /**
     * Builds a regression model using SMOreg, the SVM for regression, and 
     * evaluates it with the Evalution framework.
     */
    public void buildAndEvaluate(String trainingArff, String testArff) throws Exception {

        System.out.printf("buildAndEvaluate() called.\n");

        // Load the training and test instances.
        Instances trainingInstances = DataSource.read(trainingArff);
        Instances testInstances = DataSource.read(testArff);

        // Set the true value to be the last field in each instance.
        trainingInstances.setClassIndex(trainingInstances.numAttributes()-1);
        testInstances.setClassIndex(testInstances.numAttributes()-1);

        // Build the SMOregression model.
        SMOreg smo = new SMOreg();
        smo.buildClassifier(trainingInstances);

        // Use Weka's evaluation framework.
        Evaluation eval = new Evaluation(trainingInstances);
        eval.evaluateModel(smo, testInstances);

        // Print the options that were used in the ML algorithm.
        String[] options = smo.getOptions();
        System.out.printf("Options used:\n");
        for (String option : options) {
            System.out.printf("%s ", option);
        }
        System.out.printf("\n\n");

        // Print the algorithm details.
        System.out.printf("Algorithm:\n %s\n", smo.toString());

        // Print the evaluation results.
        System.out.printf("%s\n", eval.toSummaryString("\nResults\n=====\n", false));
    }

    /**
     * Builds a regression model using SMOreg, the SVM for regression, and 
     * tests each data instance individually to compute RMSE.
     */
    public void buildAndTestEachInstance(String trainingArff, String testArff) throws Exception {

        System.out.printf("buildAndTestEachInstance() called.\n");

        // Load the training and test instances.
        Instances trainingInstances = DataSource.read(trainingArff);
        Instances testInstances = DataSource.read(testArff);

        // Set the true value to be the last field in each instance.
        trainingInstances.setClassIndex(trainingInstances.numAttributes()-1);
        testInstances.setClassIndex(testInstances.numAttributes()-1);

        // Build the SMOregression model.
        SMOreg smo = new SMOreg();
        smo.buildClassifier(trainingInstances);

        int numTestInstances = testInstances.numInstances();

        // This variable accumulates the squared error from each test instance.
        double sumOfSquaredError = 0.0;

        // Loop over each test instance.
        for (int i = 0; i < numTestInstances; i++) {

            Instance instance = testInstances.instance(i);

            double trueValue = instance.value(testInstances.classIndex());
            double predictedValue = smo.classifyInstance(instance);

            // Uncomment the next line to see every prediction on the test instances.
            //System.out.printf("true=%10.5f, predicted=%10.5f\n", trueValue, predictedValue);

            double error = trueValue - predictedValue;
            sumOfSquaredError += (error * error);
        }

        // Print the RMSE results.
        double rmse = Math.sqrt(sumOfSquaredError / numTestInstances);
        System.out.printf("RMSE = %10.5f\n", rmse);
    }

    public static void main(String argv[]) throws Exception {

        Tester classify = new Tester();
        classify.buildAndEvaluate("../weka-3-8-1/data/cpu.arff", "../weka-3-8-1/data/cpu.arff");
        classify.buildAndTestEachInstance("../weka-3-8-1/data/cpu.arff", "../weka-3-8-1/data/cpu.arff");
    }
}

我已经编写了两个函数来训练 SMOreg 模型并通过 运行对训练数据进行预测来评估模型。

  • buildAndEvaluate() 使用 Weka 评估模型 Evaluation 框架到 运行 一套测试得到完全相同 结果作为 Explorer GUI。值得注意的是,它会产生一个 RMSE 值。

  • buildAndTestEachInstance() 通过显式评估模型 遍历每个测试实例,进行预测,计算 误差,并计算整体 RMSE。请注意,此 RMSE 匹配 来自 buildAndEvaluate() 的那一个又与那个匹配 来自 Explorer GUI。

下面是编译和 运行ning 程序的结果。

prompt> javac -cp weka.jar Tester.java

prompt> java -cp .:weka.jar Tester

buildAndEvaluate() called.
Options used:
-C 1.0 -N 0 -I weka.classifiers.functions.supportVector.RegSMOImproved -T 0.001 -V -P 1.0E-12 -L 0.001 -W 1 -K weka.classifiers.functions.supportVector.PolyKernel -E 1.0 -C 250007 

Algorithm:
 SMOreg

weights (not support vectors):
 +       0.01   * (normalized) MYCT
 +       0.4321 * (normalized) MMIN
 +       0.1847 * (normalized) MMAX
 +       0.1175 * (normalized) CACH
 +       0.0973 * (normalized) CHMIN
 +       0.0235 * (normalized) CHMAX
 -       0.0168



Number of kernel evaluations: 21945 (93.081% cached)

Results
=====

Correlation coefficient                  0.9044
Mean absolute error                     31.7392
Root mean squared error                 74.5996
Relative absolute error                 33.0908 %
Root relative squared error             46.4953 %
Total Number of Instances              209     

buildAndTestEachInstance() called.
RMSE =   74.59964