Одинаковый заголовок экземпляров ( 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.
Возможно ли что-то вроде ниже рабочего процесса?
- получить предварительно подготовленную информацию заголовка из файла arff или другого места.
- дать конструкции экземпляра эту информацию заголовка
- вызовите функцию 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)