Одинаковый заголовок экземпляров ( arff) для всех запросов к моей базе данных

Я использую InstanceQuery, SQL-запросы, для создания своих экземпляров. Но результаты моего запроса не всегда совпадают по порядку, как обычно в 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}

Мой вопрос: как я могу дать правильную информацию заголовка для конструкции Instance.

Возможно ли что-то вроде ниже рабочего процесса?

  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);
    }
}

2 ответа

Решение

Я пробовал разные подходы к моей проблеме. Но похоже, что 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);
    }

Это решает мою проблему, но мне интересно, существует ли более элегантное решение.

Я решил похожую проблему с 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" одинаковы (совместимы с машинным обучением Weka)

Другие вопросы по тегам