/*
* ConceptDriftRealStream.java
* Copyright (C) 2008 University of Waikato, Hamilton, New Zealand
* @author Albert Bifet
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package tr.gov.ulakbim.jDenetX.streams;
import tr.gov.ulakbim.jDenetX.core.InstancesHeader;
import tr.gov.ulakbim.jDenetX.core.ObjectRepository;
import tr.gov.ulakbim.jDenetX.options.AbstractOptionHandler;
import tr.gov.ulakbim.jDenetX.options.ClassOption;
import tr.gov.ulakbim.jDenetX.options.FloatOption;
import tr.gov.ulakbim.jDenetX.options.IntOption;
import tr.gov.ulakbim.jDenetX.tasks.TaskMonitor;
import weka.core.*;
import java.util.Random;
// Generator that adds concept drift to examples in a stream with
// different classes and attributes. Example: real datasets
//
// Example:
//
// ConceptDriftRealStream -s (ArffFileStream -f covtype.arff) \
// -d (ConceptDriftRealStream -s (ArffFileStream -f PokerOrig.arff) \
// -d (ArffFileStream -f elec.arff) -w 5000 -p 1000000 ) -w 5000 -p 581012
//
// s : Stream
// d : Concept drift Stream
// p : Central position of concept drift change
// w : Width of concept drift change
public class ConceptDriftRealStream extends AbstractOptionHandler implements
InstanceStream {
@Override
public String getPurposeString() {
return "Adds Concept Drift to examples in a stream.";
}
private static final long serialVersionUID = 1L;
public ClassOption streamOption = new ClassOption("stream", 's',
"Stream to add concept drift.", InstanceStream.class,
"generators.RandomTreeGenerator");
public ClassOption driftstreamOption = new ClassOption("driftstream", 'd',
"Concept drift Stream.", InstanceStream.class,
"generators.RandomTreeGenerator");
public FloatOption alphaOption = new FloatOption("alpha",
'a', "Angle alpha of change grade.", 0.0, 0.0, 90.0);
public IntOption positionOption = new IntOption("position",
'p', "Central position of concept drift change.", 0);
public IntOption widthOption = new IntOption("width",
'w', "Width of concept drift change.", 1000);
public IntOption randomSeedOption = new IntOption("randomSeed", 'r',
"Seed for random noise.", 1);
protected InstanceStream inputStream;
protected InstanceStream driftStream;
protected Random random;
protected int numberInstanceStream;
protected InstancesHeader streamHeader;
protected Instance inputInstance;
protected Instance driftInstance;
@Override
public void prepareForUseImpl(TaskMonitor monitor,
ObjectRepository repository) {
this.inputStream = (InstanceStream) getPreparedClassOption(this.streamOption);
this.driftStream = (InstanceStream) getPreparedClassOption(this.driftstreamOption);
this.random = new Random(this.randomSeedOption.getValue());
numberInstanceStream = 0;
if (this.alphaOption.getValue() != 0.0) {
this.widthOption.setValue((int) (1 / Math.tan(this.alphaOption.getValue() * Math.PI / 180)));
}
// generate header
Instances first = this.inputStream.getHeader();
Instances second = this.driftStream.getHeader();
FastVector newAttributes = new FastVector();
for (int i = 0; i < first.numAttributes() - 1; i++) {
newAttributes.addElement(first.attribute(i));
}
for (int i = 0; i < second.numAttributes() - 1; i++) {
newAttributes.addElement(second.attribute(i));
}
Attribute classLabels;
if (first.numClasses() < second.numClasses()) {
classLabels = second.classAttribute();
} else {
classLabels = first.classAttribute();
}
newAttributes.addElement(classLabels);
this.streamHeader = new InstancesHeader(new Instances(
getCLICreationString(InstanceStream.class), newAttributes, 0));
this.streamHeader.setClassIndex(this.streamHeader.numAttributes() - 1);
restart();
}
public long estimatedRemainingInstances() {
return -1;
}
public boolean hasMoreInstances() {
return true;
}
public InstancesHeader getHeader() {
return this.streamHeader;
}
public boolean isRestartable() {
return (this.inputStream.isRestartable() && this.driftStream.isRestartable());
}
public Instance nextInstance() {
numberInstanceStream++;
double numclass = 0.0;
double x = -4.0 * (double) (numberInstanceStream - this.positionOption.getValue()) / (double) this.widthOption.getValue();
double probabilityDrift = 1.0 / (1.0 + Math.exp(x));
if (this.random.nextDouble() > probabilityDrift) {
if (!this.inputStream.hasMoreInstances()) {
this.inputStream.restart();
}
this.inputInstance = this.inputStream.nextInstance();
numclass = this.inputInstance.classValue();
} else {
if (!this.driftStream.hasMoreInstances()) {
this.driftStream.restart();
}
this.driftInstance = this.driftStream.nextInstance();
numclass = this.driftInstance.classValue();
}
int m = 0;
double[] newVals = new double[this.inputInstance.numAttributes() + this.driftInstance.numAttributes() - 1];
for (int j = 0; j < this.inputInstance.numAttributes() - 1; j++, m++) {
newVals[m] = this.inputInstance.value(j);
}
for (int j = 0; j < this.driftInstance.numAttributes() - 1; j++, m++) {
newVals[m] = this.driftInstance.value(j);
}
newVals[m] = numclass;
//return new Instance(1.0, newVals);
Instance inst = new DenseInstance(1.0, newVals);
inst.setDataset(this.getHeader());
inst.setClassValue(numclass);
return inst;
}
public void restart() {
this.inputStream.restart();
this.driftStream.restart();
numberInstanceStream = 0;
this.inputInstance = this.inputStream.nextInstance();
this.driftInstance = this.driftStream.nextInstance();
}
public void getDescription(StringBuilder sb, int indent) {
// TODO Auto-generated method stub
}
}