更改 Java 将 double 写入 CSV 的代码以将 double[] 写入 CSV(用例 = WEKA 库)

Changing Java code that writes double to CSV to write double[] to CSV (use case = WEKA library)

我使用

的 WEKA 库编写了一个 Java 程序
  1. 训练class化算法
  2. 使用经过训练的算法对未标记的数据集运行预测
  3. 将结果写入 .csv 文件

问题在于它目前写出离散的 class化结果(即算法猜测某行属于哪个类别)。我想要的是写出给定 class 的概率(例如,如果我将行 class 化为 "spam" 或 "not spam" 那么我希望垃圾邮件的概率是结果)。

我的理解是,要做到这一点,我需要在我的代码中使用 distributionForInstance 而不是 classifyInstance。来自 WEKA:

If you're interested in the distribution over all the classes, use the method distributionForInstance(Instance). This method returns a double array with the probability for each class.

我 运行 遇到的问题是 classifyInstance 我正在处理 double 数据类型,而 distributionForInstance 我正在处理使用 double[] 数据类型,显然没有正确调整我的代码。

这是写出谨慎预测的工作代码:

public class runPredictions {
public static void runPredictions(ArrayList al2) throws IOException, Exception{
    // Retrieve objects
    Instances newTest = (Instances) al2.get(0);
    Classifier clf = (Classifier) al2.get(1);

    // Print status
    System.out.println("Generating predictions...");

    // create copy
    Instances labeled = new Instances(newTest);

    // label instances
    for (int i = 0; i < newTest.numInstances(); i++) {
      double clsLabel = clf.classifyInstance(newTest.instance(i));
      labeled.instance(i).setClassValue(clsLabel);

    }
    System.out.println("Predictions complete! Writing output file to csv...");
    BufferedWriter outFile = new BufferedWriter(new FileWriter("C:/Users/hackr/Desktop/silverbullet_output.csv"));

    for (int i = 0; i < labeled.size(); i++)
    {
        outFile.write(labeled.get(i).toString());
        outFile.write("\n");
    }
    System.out.println("Output file written.");
    System.out.println("Completed successfully!");
    outFile.close();    
}    
}

现在我正在处理的代码如下:

   for (int i = 0; i < labeled.size(); i++)

{
    double[] clsLabel = clf.distributionForInstance(newTest.instance(i));
    //outFile.write(labeled.get(i).toString());
    outFile.write(Double.toString(clsLabel[i]));
    outFile.write("\n");
}

并抛出一个

Index out of bounds

错误。

我还移动了 clsLabel 的创建,因为显然当数据类型更改时它无法再找到该符号,除非我将它移动到 for 循环内。

假设您的输出类似于枢轴 table,其中 class 标签作为列,并且从您的 classfier I 返回的每个 class 的得分假设,您需要遍历数组并为每个值创建一个字段,或者只列出这些值。我不知道 double[] 数组中的值如何与 class 标签相关联,但是您必须以某种方式建立这种关联。 也许如果 classifier 不能 classify,它 returns 一个空数组,这就是你得到 IOOB 异常的原因。

改写我的评论。

您从 clf.distributionForInstance(newTest.instance(i)); 返回的结果本身就是一个 double[]。这意味着不是你从分布函数中得到一个值,而是整个分布作为一个值数组。

要正确显示整体分布,您需要单独遍历结果集并打印值:

for (int i = 0; i < labeled.size(); i++) {
     double[] clsLabel = clf.distributionForInstance(newTest.instance(i));
     for(double d : clsLabel) {
         outFile.write(Double.toString(d));
     }
     outFile.write("\n");
}

假设有 2 个 类(预测的是 2 个类别,例如 "spam" 和 "not spam")以下工作:

BufferedWriter outFile = new BufferedWriter(new FileWriter("silverbullet_rro_output.csv"));
StringBuilder builder = new StringBuilder();

for (int i = 0; i < labeled.size(); i++)      
{
    double[] clsLabel = clf.distributionForInstance(newTest.instance(i));
    for(int j=0;j<2;j++){
       builder.append(clsLabel[j]+""); 
       if(j < clsLabel.length - 1)
           builder.append(",");
    }
    builder.append("\n");
}
outFile.write(builder.toString());//save the string representation
System.out.println("Output file written.");
System.out.println("Completed successfully!");
outFile.close();