在 Weka 中对单个实例进行分类(MultilayerPerceptron)

Posted

技术标签:

【中文标题】在 Weka 中对单个实例进行分类(MultilayerPerceptron)【英文标题】:Classifying Single Instance in Weka (MultilayerPerceptron) 【发布时间】:2021-07-24 05:39:10 【问题描述】:

我使用 weka.jar 版本 3.6.10 训练并创建了一个 MultilayerPerceptron 模型。我将模型文件保存到我的计算机上,现在我想用它来分类我的 Java 代码中的单个实例。我想获得属性“类”的预测。我找到了答案here 我将值更改为我需要的值。我要做的是:

import weka.classifiers.Classifier;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SparseInstance;
import weka.core.SerializationHelper;
public class JavaApplication 

    public static void main(String[] args) 
        JavaApplication q = new JavaApplication();
        double result = q.classify(-1.18,12.76,1.7297841);
        System.out.println(result);
    

    private Instance inst_co;

    public double classify(double x, double y, double z)  

        // Create attributes to be used with classifiers
        // Test the model
        double result = -1;
        try 

            FastVector attributeList = new FastVector();

            Attribute x_acc= new Attribute("x_acc");
            Attribute y_acc= new Attribute("y_acc");
            Attribute z_acc= new Attribute("z_acc");

            FastVector classVal = new FastVector();
            classVal.addElement("Walking");
            classVal.addElement("Jogging");
            classVal.addElement("Downstairs");
            classVal.addElement("Sitting");
            classVal.addElement("Upstairs");


            attributeList.addElement(x_acc);
            attributeList.addElement(y_acc);
            attributeList.addElement(z_acc);
            attributeList.addElement(new Attribute("@@class@@",classVal));

            Instances data = new Instances("TestInstances",attributeList,0);


            // Create instances for each pollutant with attribute values latitude,
            // longitude and pollutant itself
            inst_co = new SparseInstance(data.numAttributes());
            data.add(inst_co);

            // Set instance's values for the attributes "latitude", "longitude", and
            // "pollutant concentration"
            inst_co.setValue(x_acc, x);
            inst_co.setValue(y_acc, y);
            inst_co.setValue(z_acc, z);
            // inst_co.setMissing(cluster);
            

            // load classifier from file
           Classifier cls_co = (MultilayerPerceptron) SerializationHelper
                   .read("/Users/ALL-TECH/Desktop/Sensors application/FewDataGenerated/model.model");

            result = cls_co.classifyInstance(inst_co);
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        
        return result;
    

我的 arff 文件如下所示:

@RELATION fewOfDataCsv

@ATTRIBUTE x_acc  NUMERIC
@ATTRIBUTE y_acc  NUMERIC
@ATTRIBUTE z_acc  NUMERIC
@ATTRIBUTE class  Upstairs,Downstairs,Walking,Jogging,Sitting

@DATA
-1.18,12.76,1.7297841 ,Upstairs
0.93,10.99,0.08172209 ,Upstairs
0.08,11.35,0.46309182 ,Upstairs
1.88,9.47,3.405087 ,Walking
0.89,9.38,3.3778462 ,Walking
1.38,11.54,3.336985 ,Walking
2.83,3.68,-3.255263 ,Jogging
-1.8,2.45,7.082581 ,Jogging
16.63,9.89,-1.56634 ,Jogging
12.53,1.88,-6.3198414 ,Jogging
7.46,2.3,6.4 ,Sitting
7.5,2.3,6.44 ,Sitting
7.46,2.3,6.47 ,Sitting
-1.23,8.28,0.040861044 ,Downstairs
-1.92,6.28,1.1441092 ,Downstairs
-1.73,5.75,2.152015 ,Downstairs

结果(我真的不知道那个数字是从哪里来的):

run:
3.0
BUILD SUCCESSFUL (total time: 1 second)

我的代码中缺少什么?如果有人可以提供帮助,我将不胜感激。

【问题讨论】:

【参考方案1】:

在您的main 方法中,您正在调用JavaApplication.classify 方法,该方法返回分类器的分类(双精度)。而你又通过System.out.println 输出到标准输出。你为什么对数字的来源感到困惑?

Classifier.classifyInstance 方法返回一个双精度值。在回归算法的情况下,这是预测的数值,在分类算法的情况下,这是预测的类标签的基于 0 的索引。在您的情况下,数字 3.0 对应于 Jogging

【讨论】:

在我的情况下,数字 3.0 与慢跑不对应。我试图改变每个元素的位置并将慢跑放在其他地方,但数字仍然是 3.0 并且你可以在我的 arff 文件中看到第一个元素是 -1.18,12.76,1.7297841,楼上所以不要慢跑 3.0是模型的预测,对应JoggingUpstairs 是您的 ARFF 文件中存储的 实际 值。 我更改了代码中值的顺序,我将 Jogging 放在 FastVector 的末尾,然后放在顶部,但是当我运行代码时,始终给我相同的值,即 3.0 @fracpete any seggustion ?【参考方案2】:

以下是对代码的重写,以解决以下缺点:

每次进行预测时都会重新创建数据集结构 每次进行预测时都会加载模型 使用 weka.core.SparseInstance 毫无意义,因为您只有三个属性,而且您似乎总是提供它们

从 Weka Explorer 或通过命令行保存模型时,Weka 不仅将 weka.classifiers.Classifier 对象存储在该文件中,还存储训练数据的标头(又名结构)。您可以简单地将该标头用于您正在构建的 weka.core.Instance 对象的结构。

以下类期望获取模型的路径作为第一个参数,然后在构造函数中从该文件加载模型和标头。

我还为标题添加了一个 get 方法,以允许将分类标签索引(Classifier.classifyInstance 在名义类属性的情况下返回)转换为实际的类标签字符串。

public class JavaApplication 

  private Instances header;

  private Classifier model;

  public JavaApplication(String modelPath) throws Exception 
    Object[] objects = SerializationHelper.readAll(modelPath);
    model = (Classifier) objects[0];
    header = (Instances) objects[1];
  

  public Instances getHeader() 
    return header;
  

  public int classify(double x, double y, double z)  
    int result = -1;
    try 
      double[] values = new double[header.numAttributes()];
      values[0] = x;
      values[1] = y;
      values[2] = z;
      Instance inst = new DenseInstance(1.0, values);
      inst.setDataset(header);
      result = (int) model.classifyInstance(inst);
    
    catch (Exception e) 
      System.err.println("Failed to classify instance!");
      e.printStackTrace();
    
    return result;
  

  public static void main(String[] args) throws Exception 
    JavaApplication q = new JavaApplication(args[0]);
    int labelIndex = q.classify(-1.18, 12.76, 1.7297841);
    System.out.println(labelIndex);
    System.out.println(q.getHeader().classAttribute().value(labelIndex));
  

【讨论】:

感谢您抽出宝贵时间,但您的代码对我不起作用,它在线程“main” java.lang.ArrayIndexOutOfBoundsException: 1 .. in this ligne (header = (Instances) objects[1];) 所以我想现在问题可能是我的模型.. 使用 Weka Explorer 或命令行训练/保存您的模型,然后标题将出现(模型文件中的第二个对象)。

以上是关于在 Weka 中对单个实例进行分类(MultilayerPerceptron)的主要内容,如果未能解决你的问题,请参考以下文章

使用 NaiveBayes 分类器对 Weka 中的一个实例进行分类

如何在 Weka 中对训练和测试数据集进行分类

weka中新实例的分类

Weka 对实例进行分类

尝试使用带有 Weka 的 Java 对新实例进行分类时出错 - 未定义输出实例格式

Weka中的实例分类