/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.operator.learner.functions.kernel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.operator.Model;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.learner.functions.kernel.functions.Kernel;
import com.rapidminer.operator.performance.EstimatedPerformance;
import com.rapidminer.operator.performance.PerformanceVector;
import com.rapidminer.tools.LoggingHandler;
import com.rapidminer.tools.RandomGenerator;
import com.rapidminer.tools.math.optimization.ec.es.ESOptimization;
import com.rapidminer.tools.math.optimization.ec.es.Individual;
/**
* Evolutionary Strategy approach for optimization of the logistic regression problem.
*
* @author Ingo Mierswa
* @version $Id: KernelLogisticRegressionOptimization.java,v 1.5 2008/05/09 19:23:01 ingomierswa Exp $
*/
public class KernelLogisticRegressionOptimization extends ESOptimization {
/** Number smaller than this number are regarded as zero. */
private final static double IS_ZERO = 1e-8;
private ExampleSet exampleSet;
private Kernel kernel;
private double[] ys;
private double c;
private Attribute label;
private Attribute weight;
private boolean multiobjective = false;
/** Creates a new evolutionary SVM optimization. */
public KernelLogisticRegressionOptimization(
ExampleSet exampleSet, // training data
Kernel kernel, // kernel
double c,
int initType, // start population creation type para
int maxIterations, int generationsWithoutImprovement, int popSize, // GA paras
int selectionType, double tournamentFraction, boolean keepBest, // selection paras
int mutationType, // type of mutation
double crossoverProb,
boolean showConvergencePlot,
RandomGenerator random,
LoggingHandler logging) {
super(0, 1.0, popSize, exampleSet.size(),
initType, maxIterations, generationsWithoutImprovement, selectionType, tournamentFraction, keepBest,
mutationType, crossoverProb, showConvergencePlot, random, logging);
if (selectionType == NON_DOMINATED_SORTING_SELECTION) {
multiobjective = true;
} else {
multiobjective = false;
}
this.exampleSet = exampleSet;
this.kernel = kernel;
this.kernel.init(this.exampleSet);
this.c = c;
this.label = exampleSet.getAttributes().getLabel();
this.weight = exampleSet.getAttributes().getWeight();
this.ys = new double[exampleSet.size()];
int counter = 0;
for (Example e : exampleSet) {
ys[counter++] = e.getLabel() == label.getMapping().getPositiveIndex() ? 1 : 0;
}
}
public PerformanceVector evaluateIndividual(Individual individual) {
double[] alphas = individual.getValues();
double marginSum = 0.0d;
for (int i = 0; i < ys.length; i++) {
if (alphas[i] == 0.0d)
continue;
for (int j = 0; j < ys.length; j++) {
if (alphas[j] == 0.0d)
continue;
marginSum += (alphas[i] * alphas[j] * ys[i] * ys[j] * kernel.getDistance(i, j));
}
}
double errorSum = 0.0d;
int i = 0;
for (Example example : exampleSet) {
double delta = alphas[i];
if (!multiobjective)
delta /= c;
if (delta > 0.0d) {
double weightValue = 1.0d;
if (weight != null)
weightValue = example.getValue(weight);
// the following lines deliver the same results
//double currentResult = weightValue * (ys[i] * Math.log(delta) + (1.0d - ys[i]) * Math.log(1.0d - delta) + delta);
double currentResult = weightValue * (delta * Math.log(delta) + (1.0d - delta) * Math.log(1.0d - delta));
if (!Double.isNaN(currentResult))
errorSum += currentResult;
}
i++;
}
PerformanceVector performanceVector = new PerformanceVector();
if (!multiobjective) {
double fitness = marginSum + c * errorSum;
performanceVector.addCriterion(new EstimatedPerformance("log_reg_fitness", fitness, 1, false));
} else {
performanceVector.addCriterion(new EstimatedPerformance("log_reg_margin", marginSum, 1, false));
performanceVector.addCriterion(new EstimatedPerformance("log_reg_error", errorSum, 1, false));
}
return performanceVector;
}
public Model train() throws OperatorException {
optimize();
return getModel(getBestValuesEver());
}
/**
* Returns a model containing all support vectors, i.e. the examples with
* non-zero alphas.
*/
private Model getModel(double[] alphas) {
// calculate support vectors
Iterator<Example> reader = exampleSet.iterator();
List<SupportVector> supportVectors = new ArrayList<SupportVector>();
int index = 0;
while (reader.hasNext()) {
double currentAlpha = alphas[index];
Example currentExample = reader.next();
if (currentAlpha != 0.0d) {
double[] x = new double[exampleSet.getAttributes().size()];
int a = 0;
for (Attribute attribute : exampleSet.getAttributes())
x[a++] = currentExample.getValue(attribute);
supportVectors.add(new SupportVector(x, ys[index], currentAlpha));
}
index++;
}
// calculate all sum values
double[] sum = new double[exampleSet.size()];
reader = exampleSet.iterator();
index = 0;
while (reader.hasNext()) {
Example current = reader.next();
double[] x = new double[exampleSet.getAttributes().size()];
int a = 0;
for (Attribute attribute : exampleSet.getAttributes())
x[a++] = current.getValue(attribute);
sum[index] = kernel.getSum(supportVectors, x);
index++;
}
// calculate b (from Stefan's mySVM code)
double bSum = 0.0d;
int bCounter = 0;
for (int i = 0; i < alphas.length; i++) {
if ((ys[i] * alphas[i] - c < -IS_ZERO) && (ys[i] * alphas[i] > IS_ZERO)) {
bSum += ys[i] - sum[i];
bCounter++;
} else if ((ys[i] * alphas[i] + c > IS_ZERO) && (ys[i] * alphas[i] < -IS_ZERO)) {
bSum += ys[i] - sum[i];
bCounter++;
}
}
if (bCounter == 0) {
// unlikely
bSum = 0.0d;
for (int i = 0; i < alphas.length; i++) {
if ((ys[i] * alphas[i] < IS_ZERO) && (ys[i] * alphas[i] > -IS_ZERO)) {
bSum += ys[i] - sum[i];
bCounter++;
}
}
if (bCounter == 0) {
// even unlikelier
bSum = 0.0d;
for (int i = 0; i < alphas.length; i++) {
bSum += ys[i] - sum[i];
bCounter++;
}
}
}
return new KernelLogisticRegressionModel(exampleSet, supportVectors, kernel, bSum / bCounter);
}
}