package de.lmu.ifi.dbs.elki.math.statistics.distribution.estimator.meta;
/*
This file is part of ELKI:
Environment for Developing KDD-Applications Supported by Index-Structures
Copyright (C) 2013
Ludwig-Maximilians-Universität München
Lehr- und Forschungseinheit für Datenbanksysteme
ELKI Development Team
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 .
*/
import java.util.Arrays;
import de.lmu.ifi.dbs.elki.math.statistics.distribution.Distribution;
import de.lmu.ifi.dbs.elki.math.statistics.distribution.estimator.DistributionEstimator;
import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.ArrayLikeUtil;
import de.lmu.ifi.dbs.elki.utilities.datastructures.arraylike.NumberArrayAdapter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.AbstractParameterizer;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.OptionID;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.GreaterConstraint;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.constraints.LessConstraint;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameterization.Parameterization;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.DoubleParameter;
import de.lmu.ifi.dbs.elki.utilities.optionhandling.parameters.ObjectParameter;
/**
* Trimmed wrapper around other estimators. Sorts the data, trims it, then
* analyzes it using another estimator.
*
* @author Erich Schubert
*
* @param Distribution type
*/
public class TrimmedEstimator implements DistributionEstimator {
/**
* Distribution estimator to use.
*/
private DistributionEstimator inner;
/**
* Amount of data to trim.
*/
private double trim;
/**
* Constructor.
*
* @param inner Inner estimator.
* @param trim Trimming parameter.
*/
public TrimmedEstimator(DistributionEstimator inner, double trim) {
super();
this.inner = inner;
this.trim = trim;
}
@Override
public D estimate(A data, NumberArrayAdapter, A> adapter) {
// We first need the basic parameters:
int len = adapter.size(data);
final int cut = ((int) (len * trim)) >> 1;
// X positions of samples
double[] x = new double[len];
for (int i = 0; i < len; i++) {
final double val = adapter.getDouble(data, i);
x[i] = val;
}
// Sort our copy.
Arrays.sort(x);
{ // Trim:
// TODO: is it more efficient to just copy, or instead use a trimmed array
// adapter?
double[] trimmed = new double[len - 2 * cut];
System.arraycopy(x, cut, trimmed, 0, trimmed.length);
x = trimmed;
len = trimmed.length;
}
return inner.estimate(x, ArrayLikeUtil.DOUBLEARRAYADAPTER);
}
@Override
public Class super D> getDistributionClass() {
return inner.getDistributionClass();
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "(" + inner.toString() + ", trim=" + trim + ")";
}
/**
* Parameterization class.
*
* @author Erich Schubert
*
* @apiviz.exclude
*
* @param Distribution type
*/
public static class Parameterizer extends AbstractParameterizer {
/**
* Option for the class to use on the trimmed sample.
*/
public static final OptionID INNER_ID = new OptionID("trimmedestimate.inner", "Estimator to use on the trimmed data.");
/**
* Option for specifying the amount of data to trim.
*/
public static final OptionID TRIM_ID = new OptionID("trimmedestimate.trim", "Relative amount of data to trim on each end, must be 0 < trim < 0.5");
/**
* Distribution estimator to use.
*/
private DistributionEstimator inner;
/**
* Amount of data to trim.
*/
private double trim;
@Override
protected void makeOptions(Parameterization config) {
super.makeOptions(config);
ObjectParameter> innerP = new ObjectParameter<>(INNER_ID, DistributionEstimator.class);
if (config.grab(innerP)) {
inner = innerP.instantiateClass(config);
}
DoubleParameter trimP = new DoubleParameter(TRIM_ID);
trimP.addConstraint(new GreaterConstraint(0.));
trimP.addConstraint(new LessConstraint(0.5));
if (config.grab(trimP)) {
trim = trimP.doubleValue();
}
}
@Override
protected TrimmedEstimator makeInstance() {
return new TrimmedEstimator<>(inner, trim);
}
}
}