0

我正在使用InstanceQuery和 SQL 查询来构建我的Instances。但是我的查询结果并不总是与 SQL 中的正常顺序相同。由于这个由不同 SQL 构造的实例具有不同的标头。一个简单的例子可以在下面看到。我怀疑我的结果会因为这种行为而改变。

标题 1

@attribute duration numeric
@attribute protocol_type {tcp,udp}
@attribute service {http,domain_u}
@attribute flag {SF}

标题 2

@attribute duration numeric
@attribute protocol_type {tcp}
@attribute service {pm_dump,pop_2,pop_3}
@attribute flag {SF,S0,SH}

我的问题是:如何为实例构造提供正确的标头信息。

类似下面的工作流程是可能的吗?

  1. 从 arff 文件或其他地方获取预先准备好的头信息。
  2. 给实例构造这个头信息
  3. 调用 sql 函数并获取实例(标头 + 数据)

我正在使用以下 sql 函数从数据库中获取实例。

public static Instances getInstanceDataFromDatabase(String pSql
                                      ,String pInstanceRelationName){
    try {
        DatabaseUtils utils = new DatabaseUtils();

        InstanceQuery query = new InstanceQuery();

        query.setUsername(username);
        query.setPassword(password);
        query.setQuery(pSql);

        Instances data = query.retrieveInstances();
        data.setRelationName(pInstanceRelationName);

        if (data.classIndex() == -1)
        {
              data.setClassIndex(data.numAttributes() - 1);
        }
        return data;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
4

2 回答 2

0

我尝试了各种方法来解决我的问题。但似乎 weka 内部 API 目前不允许解决此问题。为了我的目的,我修改了 weka.core.Instances 附加命令行代码。此答案中也给出了此代码

据此,这是我的解决方案。我创建了一个 SampleWithKnownHeader.arff 文件,其中包含正确的标头值。我用以下代码阅读了这个文件。

public static Instances getSampleInstances() {
    Instances data = null;
    try {
        BufferedReader reader = new BufferedReader(new FileReader(
                "datas\\SampleWithKnownHeader.arff"));
        data = new Instances(reader);
        reader.close();
        // setting class attribute
        data.setClassIndex(data.numAttributes() - 1);
    }
    catch (Exception e) {
        throw new RuntimeException(e);
    } 
    return data;

}

之后,我使用以下代码创建实例。我必须使用 StringBuilder 和实例的字符串值,然后将相应的字符串保存到文件中。

public static void main(String[] args) {

    Instances SampleInstance = MyUtilsForWeka.getSampleInstances();

    DataSource source1 = new DataSource(SampleInstance);

    Instances data2 = InstancesFromDatabase
            .getInstanceDataFromDatabase(DatabaseQueries.WEKALIST_QUESTION1);

    MyUtilsForWeka.saveInstancesToFile(data2, "fromDatabase.arff");

    DataSource source2 = new DataSource(data2);

    Instances structure1;
    Instances structure2;
    StringBuilder sb = new StringBuilder();
    try {
        structure1 = source1.getStructure();
        sb.append(structure1);
        structure2 = source2.getStructure();
        while (source2.hasMoreElements(structure2)) {
            String elementAsString = source2.nextElement(structure2)
                    .toString();
            sb.append(elementAsString);
            sb.append("\n");

        }

    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }

    MyUtilsForWeka.saveInstancesToFile(sb.toString(), "combined.arff");

}

我将实例保存到文件代码如下。

public static void saveInstancesToFile(String contents,String filename) {

     FileWriter fstream;
    try {
        fstream = new FileWriter(filename);
      BufferedWriter out = new BufferedWriter(fstream);
      out.write(contents);
      out.close();
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }

这解决了我的问题,但我想知道是否存在更优雅的解决方案。

于 2012-08-08T20:34:31.640 回答
0

我用过滤器解决了一个类似的问题,Add它允许将属性添加到Instances. 您需要为Attibute两个数据集添加正确的正确值列表(在我的情况下 - 仅用于测试数据集):

加载训练和测试数据:

/* "train" contains labels and data */
/* "test" contains data only */
CSVLoader csvLoader = new CSVLoader();
csvLoader.setFile(new File(trainFile));
Instances training = csvLoader.getDataSet();
csvLoader.reset();
csvLoader.setFile(new File(predictFile));
Instances test = csvLoader.getDataSet();

Add使用过滤器设置新属性:

Add add = new Add();
/* the name of the attribute must be the same as in "train"*/
add.setAttributeName(training.attribute(0).name());
/* getValues returns a String with comma-separated values of the attribute */
add.setNominalLabels(getValues(training.attribute(0)));
/* put the new attribute to the 1st position, the same as in "train"*/
add.setAttributeIndex("1");
add.setInputFormat(test);
/* result - a compatible with "train" dataset */
test = Filter.useFilter(test, add);

结果“train”和“test”的header是一样的(兼容Weka机器学习)

于 2014-11-11T22:20:28.887 回答