所有数据库查询的相同实例标头(arff)

时间:2012-08-03 09:22:46

标签: weka

我正在使用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函数并获取实例(标题+数据)
  4. 我正在使用以下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);
        }
    }
    

2 个答案:

答案 0 :(得分:0)

我尝试了各种解决问题的方法。但似乎weka内部API现在不允许解决这个问题。为了我的目的,我修改了weka.core.Instances附加命令行代码。此代码也在此answer

中给出

根据这个,这是我的解决方案。我创建了一个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);
    }

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

答案 1 :(得分: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);

结果,"训练"和"测试"是相同的(兼容Weka机器学习)