2015-05-22 3 views
0

Я пытаюсь создать собственный пакетный фильтр, который расширяет SimpleBatchFilter. Тем не менее, я столкнулся с проблемой запуска его во второй раз, чтобы получить инвертированный вывод. Вот соответствующий код и ошибка я получаю после того, как обе трассы будут завершены:Пользовательский пакетный фильтр в weka

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 79, Size: 79 
    at java.util.ArrayList.rangeCheck(ArrayList.java:653) 
    at java.util.ArrayList.get(ArrayList.java:429) 
    at weka.core.Attribute.addStringValue(Attribute.java:994) 
    at weka.core.StringLocator.copyStringValues(StringLocator.java:155) 
    at weka.core.StringLocator.copyStringValues(StringLocator.java:91) 
    at weka.filters.Filter.copyValues(Filter.java:373) 
    at weka.filters.Filter.push(Filter.java:290) 
    at weka.filters.SimpleBatchFilter.batchFinished(SimpleBatchFilter.java:266) 
    at weka.filters.Filter.useFilter(Filter.java:667) 
    at likeability.Main.main(Main.java:30) 

А вот соответствующий код:

public class TestFilter extends SimpleBatchFilter { 

    private Attribute a; 
    private Attribute b; 
    private int sampleSizePercent = 15; 
    private boolean invert = false; 
    private int seed = 1; 

    @Override 
    protected Instances process(Instances inst) throws Exception { 
     ArrayList<Instances> partitionsA = partition(inst, a); 
     ArrayList<Instances> partitions = new ArrayList<Instances>(); 
     for(Instances data: partitionsA) { 
      partitions.addAll(partition(data, b)); 
     } 

     return getTestSet(partitions); 
    } 

    /* 
    * Partitions the data so that there's only one nominal value of the 
    * attribute a in one partition. 
    */ 
    private ArrayList<Instances> partition(Instances data, Attribute att) throws Exception { 
     ArrayList<Instances> instances = new ArrayList<Instances>(); 
     for (int i = 0; i < att.numValues(); i++){ 
      RemoveWithValues rm = new RemoveWithValues(); 
      rm.setAttributeIndex(Integer.toString(att.index()+1)); 
      rm.setInvertSelection(true); 
      rm.setNominalIndices(Integer.toString(i+1)); 
      rm.setInputFormat(data); 
      instances.add(Filter.useFilter(data, rm)); 
     } 
     return instances; 
    } 

    private Instances getTestSet(List<Instances> insts) throws Exception { 
     Instances output = new Instances(insts.get(0), 0); 

     for(Instances inst: insts) { 
      Resample filter = new Resample(); 
      filter.setRandomSeed(seed); 
      filter.setNoReplacement(true); 
      filter.setInvertSelection(invert); 
      filter.setSampleSizePercent(sampleSizePercent); 
      filter.setInputFormat(inst); 
      Instances curr = Filter.useFilter(inst, filter); 
      System.out.println(inst.size() + " " + curr.size()); 
      output.addAll(curr); 
     } 
     return output; 

    } 

    @Override 
    protected Instances determineOutputFormat(Instances arg) throws Exception { 
     return new Instances(arg, 0); 
    } 

    @Override 
    public String globalInfo() { 
     return "A filter which partitions the data so that each partition contains" 
       + " only instances with one value of attribute a and b, then takes " 
       + "a random subset of values from each partition and merges them to" 
       + " produce the final set."; 
    } 

    public Capabilities getCapabilities() { 
     Capabilities result = super.getCapabilities(); 
     result.enableAllAttributes(); 
     result.enableAllClasses(); 
     result.enable(Capability.NO_CLASS); // filter doesn't need class to be set 
     return result; 
     } 
    //Main and getters and setters 

} 

И это, как я это называю:

TestFilter filter = new TestFilter(); 
    filter.setA(data.attribute("gender")); 
    filter.setB(data.attribute("age")); 
    filter.setInputFormat(data); 
    Instances test = Filter.useFilter(data, filter); 
    filter.setInvert(true); 
    filter.setInputFormat(data); 
    Instances train = Filter.useFilter(data, filter); 

Мне кажется довольно глупым, что мне нужно будет использовать эти две линии между вызовами. Я подозреваю, что должен использовать isBatchFinished(), значит ли это, что я должен реализовать его, расширяя BatchFilter, а не SimpleBatchFilter? Было бы также полезно увидеть некоторые успешные реализации, так как единственные, которые я мог найти там, где находятся в руководстве WEKA.

ответ

0

Я решил это, расширив фильтр и изменив функцию процесса на batchFinished(). Я отправляю этот ответ, так как я не нашел пример пользовательского фильтра в другом месте.

@Override 
public boolean batchFinished() throws Exception { 
    if(isFirstBatchDone()) { 
     invert = true; 
    } 
    if (getInputFormat() == null) 
     throw new NullPointerException("No input instance format defined"); 
    Instances inst = getInputFormat(); 
    ArrayList<Instances> partitionsA = partition(inst, a); 
    ArrayList<Instances> partitions = new ArrayList<Instances>(); 
    for(Instances data: partitionsA) { 
     partitions.addAll(partition(data, b)); 
    } 

private void getTestSet(List<Instances> insts) throws Exception { 

    for(Instances inst: insts) { 
     Resample filter = new Resample(); 
     filter.setRandomSeed(seed); 
     filter.setNoReplacement(true); 
     filter.setInvertSelection(invert); 
     filter.setSampleSizePercent(sampleSizePercent); 
     filter.setInputFormat(inst); 
     Instances curr = Filter.useFilter(inst, filter); 
     System.out.println(inst.size() + " " + curr.size()); 
     curr.forEach((i) -> push(i)); 
    } 
} 

@Override 
public boolean setInputFormat(Instances arg) throws Exception { 
    super.setInputFormat(arg); 
    Instances outputFormat = new Instances(arg, 0); 
    setOutputFormat(outputFormat); 
    return true; 
} 
Смежные вопросы