package de.tud.inf.operator.learner.functions.weka.gaussianprocess;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.set.ConditionedExampleSet;
import com.rapidminer.example.set.HeaderExampleSet;
import com.rapidminer.example.set.NoMissingLabelsCondition;
import com.rapidminer.example.set.ReplaceMissingExampleSet;
import com.rapidminer.operator.IOContainer;
import com.rapidminer.operator.IOObject;
import com.rapidminer.operator.Model;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.OperatorDescription;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.learner.AbstractLearner;
import com.rapidminer.operator.learner.LearnerCapability;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.Kernel;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelCauchy;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelEpanechnikov;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelGaussianCombination;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelLaplace;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelMultiquadric;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelPoly;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelRadial;
import com.rapidminer.operator.learner.functions.kernel.rvm.kernel.KernelSigmoid;
import com.rapidminer.operator.preprocessing.PreprocessingOperator;
import com.rapidminer.operator.preprocessing.normalization.Normalization;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeCategory;
import com.rapidminer.parameter.ParameterTypeDouble;
import com.rapidminer.tools.OperatorService;
public class GaussianProcess extends AbstractLearner {
/*
* Parameter Constants
*/
/** indicates if classifier is run in debug mode */
public static final String PARAMETER_D = "Debug_Mode";
/** Level of Gaussian Noise */
public static final String PARAMETER_L = "L";
/** indicates wether to normalize, standardize or none */
public static final String PARAMETER_N = "N";
/* The Kernel to use */
public static final String PARAMETER_K = "Kernel";
/** The parameter name for "The kind of kernel." */
public static final String PARAMETER_KERNEL_TYPE = "kernel_type";
/**
* The parameter name for "The lengthscale r for rbf kernel functions
* (exp{-1.0 * r^-2 * ||x - bla||})."
*/
public static final String PARAMETER_KERNEL_LENGTHSCALE = "kernel_lengthscale";
/** The parameter name for "The degree used in the poly kernel." */
public static final String PARAMETER_KERNEL_DEGREE = "kernel_degree";
/** The parameter name for "The bias used in the poly kernel." */
public static final String PARAMETER_KERNEL_BIAS = "kernel_bias";
/**
* The parameter name for "The SVM kernel parameter sigma1
* (Epanechnikov, Gaussian Combination, Multiquadric)."
*/
public static final String PARAMETER_KERNEL_SIGMA1 = "kernel_sigma1";
/**
* The parameter name for "The SVM kernel parameter sigma2 (Gaussian
* Combination)."
*/
public static final String PARAMETER_KERNEL_SIGMA2 = "kernel_sigma2";
/**
* The parameter name for "The SVM kernel parameter sigma3 (Gaussian
* Combination)."
*/
public static final String PARAMETER_KERNEL_SIGMA3 = "kernel_sigma3";
/**
* The parameter name for "The SVM kernel parameter shift (polynomial,
* Multiquadric)."
*/
public static final String PARAMETER_KERNEL_SHIFT = "kernel_shift";
/** The parameter name for "The SVM kernel parameter a (neural)." */
public static final String PARAMETER_KERNEL_A = "kernel_a";
/** The parameter name for "The SVM kernel parameter b (neural)." */
public static final String PARAMETER_KERNEL_B = "kernel_b";
public static final String[] KERNEL_TYPES = { "rbf", "cauchy", "laplace",
"poly", "sigmoid", "Epanechnikov", "gaussian combination",
"multiquadric" };
/** The parameter name for nominal transformation */
public static final String PARAMETER_NOMINAL_TRANSFORMATION = "nominal transformation";
public static final String[] TRANSFORMATION_TYPES = { "Nominal to Binary",
"Nominal To Numeric" };
public static final int TRANSFORMATION_TO_BINARY = 0;
public static final int TRANSFORMATION_TO_NUMERIC = 1;
public static final String OPERATOR_NOMINAL2BINOMINAL = "Nominal2Binominal";
public static final String OPERATOR_NOMINAL2NUMERIC = "Nominal2Numeric";
/*
* Filter Constants
*/
/** normalizes the data */
public static final int FILTER_NORMALIZE = 0;
/** standardizes the data */
public static final int FILTER_STANDARDIZE = 1;
/** no filter */
public static final int FILTER_NONE = 2;
/** Whether to normalize/standardize/neither */
private int filterType = FILTER_NORMALIZE;
/**
* Turn off all checks and conversions? Turning them off assumes that data
* is purely numeric, doesn't contain any missing values, and has a numeric
* class.
*/
private boolean checksTurnedOff = false;
/** Gaussian Noise Value. */
private double delta = 1.0;
/** The kernel to use */
private Kernel kernel;
/** The training data. */
private double avgTarget;
/** The covariance matrix. */
private Jama.Matrix covarianceMatrix;
/** The vector of target values. */
private Jama.Matrix targetVector;
/*
* private Class Attributes
*/
private Normalization normalize;
public GaussianProcess(OperatorDescription description) {
super(description);
}
public Model learn(ExampleSet exampleSet) throws OperatorException {
double[][] inputVectors;
Model normalizationModel = null;
Model nominalTransformingModel = null;
ExampleSet originalHeader = (HeaderExampleSet)new HeaderExampleSet(exampleSet).clone();
setOptions();
try {
/* check the set of training instances */
if (!checksTurnedOff) {
exampleSet = new ConditionedExampleSet(exampleSet,
new NoMissingLabelsCondition(exampleSet, null));
}
if (!checksTurnedOff) {
/* replace missing values */
exampleSet = new ReplaceMissingExampleSet(exampleSet);
}
/* checks if nominal attributes exist */
boolean onlyNumeric = true;
if (!checksTurnedOff) {
for (Attribute attr : exampleSet.getAttributes()) {
if (attr.isNominal()) {
onlyNumeric = false;
break;
}
}
}
if (!onlyNumeric) {
/* Transforms all nominal attributes */
Operator nominalTransformation;
switch (getParameterAsInt(PARAMETER_NOMINAL_TRANSFORMATION)) {
case TRANSFORMATION_TO_BINARY:
nominalTransformation = OperatorService
.createOperator(OPERATOR_NOMINAL2BINOMINAL);
break;
case TRANSFORMATION_TO_NUMERIC:
nominalTransformation = OperatorService
.createOperator(OPERATOR_NOMINAL2NUMERIC);
break;
default:
nominalTransformation = OperatorService
.createOperator(OPERATOR_NOMINAL2BINOMINAL);
}
nominalTransformation.setParameter(
PreprocessingOperator.PARAMETER_CREATE_VIEW,
Boolean.FALSE.toString());
nominalTransformation
.setParameter(
PreprocessingOperator.PARAMETER_RETURN_PREPROCESSING_MODEL,
Boolean.TRUE.toString());
IOContainer result = nominalTransformation
.apply(new IOContainer(new IOObject[] { exampleSet }));
nominalTransformingModel = result.get(Model.class);
exampleSet = result.get(ExampleSet.class);
}
/*
* normalize or standardize the examples in the exanple set
*/
if (!(filterType == FILTER_NONE)) {
normalize = OperatorService.createOperator(Normalization.class);
normalize.setParameter(Normalization.PARAMETER_CREATE_VIEW,
Boolean.TRUE.toString());
normalize.setParameter(
Normalization.PARAMETER_RETURN_PREPROCESSING_MODEL,
Boolean.TRUE.toString());
if (filterType != FILTER_STANDARDIZE) {
normalize.setParameter(Normalization.PARAMETER_Z_TRANSFORM,
"false");
}
IOContainer container = normalize.apply(new IOContainer(
new IOObject[] { exampleSet }));
normalizationModel = container.get(Model.class);
exampleSet = normalizationModel.apply(exampleSet);
}
// Build Inverted Covariance Matrix
covarianceMatrix = new Jama.Matrix(exampleSet.size(), exampleSet
.size());
double sum = 0.0;
double kv;
inputVectors = buildInputVector(exampleSet);
int k = 0;
for (Example ex : exampleSet) {
sum += ex.getLabel();
for (int j = 0; j < k; j++) {
kv = kernel.eval(inputVectors[k], inputVectors[j]);
covarianceMatrix.set(k, j, kv);
covarianceMatrix.set(j, k, kv);
}
kv = kernel.eval(inputVectors[k], inputVectors[k]);
covarianceMatrix.set(k, k, kv + (delta * delta));
k++;
}
avgTarget = sum / exampleSet.size();
Jama.LUDecomposition luRM = new Jama.LUDecomposition(
covarianceMatrix);
if (!luRM.isNonsingular())
throw new OperatorException("Singular Matrix?!?");
Jama.Matrix iMatRM = Jama.Matrix.identity(exampleSet.size(),
exampleSet.size());
covarianceMatrix = luRM.solve(iMatRM);
targetVector = new Jama.Matrix(exampleSet.size(), 1);
{
int i = 0;
for (Example ex : exampleSet) {
targetVector.set(i, 0, ex.getLabel() - avgTarget);
i++;
}
}
targetVector = covarianceMatrix.times(targetVector);
} catch (Exception e) {
throw new OperatorException(e.getMessage(), e.getCause());
}
return new GaussianProcessesModel(exampleSet, inputVectors, kernel,
normalizationModel, avgTarget, covarianceMatrix, targetVector,
nominalTransformingModel,originalHeader);
}
//@Override
public boolean supportsCapability(LearnerCapability capability) {
if (capability == LearnerCapability.POLYNOMINAL_ATTRIBUTES
|| capability == LearnerCapability.BINOMINAL_ATTRIBUTES
|| capability == LearnerCapability.NUMERICAL_ATTRIBUTES
|| capability == LearnerCapability.NUMERICAL_CLASS)
return true;
return false;
}
@Override
public List<ParameterType> getParameterTypes() {
List<ParameterType> types = super.getParameterTypes();
ParameterType type;
type = new ParameterTypeCategory(PARAMETER_NOMINAL_TRANSFORMATION,
"The way nominal attributes should be transformed",
TRANSFORMATION_TYPES, 0);
type.setExpert(false);
types.add(type);
types.add(new ParameterTypeDouble(PARAMETER_L,
"Level of Gaussian Noise", Double.NEGATIVE_INFINITY,
Double.POSITIVE_INFINITY, 1.0));
types.add(new ParameterTypeCategory(PARAMETER_N,
"Whether to normalize, standardize or none", new String[] {
"normalize", "standardize", "none" }, 0));
type = new ParameterTypeCategory(PARAMETER_KERNEL_TYPE,
"The kind of kernel.", KERNEL_TYPES, 0);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(
PARAMETER_KERNEL_LENGTHSCALE,
"The lengthscale r for rbf kernel functions (exp{-1.0 * r^-2 * ||x - y||}).",
0, Double.POSITIVE_INFINITY, 1.0);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_DEGREE,
"The degree used in the poly kernel.", 0.0d,
Double.POSITIVE_INFINITY, 2.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_BIAS,
"The bias used in the poly kernel.", 0,
Double.POSITIVE_INFINITY, 1.0);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(
PARAMETER_KERNEL_SIGMA1,
"The SVM kernel parameter sigma1 (Epanechnikov, Gaussian Combination, Multiquadric).",
0.0d, Double.POSITIVE_INFINITY, 1.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_SIGMA2,
"The SVM kernel parameter sigma2 (Gaussian Combination).",
0.0d, Double.POSITIVE_INFINITY, 0.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_SIGMA3,
"The SVM kernel parameter sigma3 (Gaussian Combination).",
0.0d, Double.POSITIVE_INFINITY, 2.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_SHIFT,
"The SVM kernel parameter shift (polynomial, Multiquadric).",
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_A,
"The SVM kernel parameter a (neural).",
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 1.0d);
type.setExpert(false);
types.add(type);
type = new ParameterTypeDouble(PARAMETER_KERNEL_B,
"The SVM kernel parameter b (neural).",
Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0d);
type.setExpert(false);
types.add(type);
return types;
}
private void setOptions() throws OperatorException {
/* set filter type */
filterType = getParameterAsInt(PARAMETER_N);
/* set gaussian noise value */
delta = getParameterAsDouble(PARAMETER_L);
/** create the Kernel **/
this.kernel = createKernel();
}
public com.rapidminer.operator.learner.functions.kernel.rvm.kernel.Kernel createKernel()
throws OperatorException {
Kernel kernel = null;
double lengthScale = getParameterAsDouble(PARAMETER_KERNEL_LENGTHSCALE);
double bias = getParameterAsDouble(PARAMETER_KERNEL_BIAS);
double degree = getParameterAsDouble(PARAMETER_KERNEL_DEGREE);
double a = getParameterAsDouble(PARAMETER_KERNEL_A);
double b = getParameterAsDouble(PARAMETER_KERNEL_B);
double sigma1 = getParameterAsDouble(PARAMETER_KERNEL_SIGMA1);
double sigma2 = getParameterAsDouble(PARAMETER_KERNEL_SIGMA2);
double sigma3 = getParameterAsDouble(PARAMETER_KERNEL_SIGMA3);
double shift = getParameterAsDouble(PARAMETER_KERNEL_SHIFT);
switch (getParameterAsInt(PARAMETER_KERNEL_TYPE)) {
case 0:
kernel = new KernelRadial(lengthScale);
break;
case 1:
kernel = new KernelCauchy(lengthScale);
break;
case 2:
kernel = new KernelLaplace(lengthScale);
break;
case 3:
kernel = new KernelPoly(lengthScale, bias, degree);
break;
case 4:
kernel = new KernelSigmoid(a, b);
break;
case 5:
kernel = new KernelEpanechnikov(sigma1, degree);
break;
case 6:
kernel = new KernelGaussianCombination(sigma1, sigma2, sigma3);
break;
case 7:
kernel = new KernelMultiquadric(sigma1, shift);
break;
default:
kernel = new KernelRadial(lengthScale);
}
return kernel;
}
private double[][] buildInputVector(ExampleSet e) {
double vector[][] = new double[e.size()][e.getAttributes().size()];
int i = 0;
for (Example ex : e) {
int j = 0;
for (Attribute att : e.getAttributes()) {
vector[i][j] = ex.getValue(att);
j++;
}
i++;
}
return vector;
}
}