package dr.math.distributions;
import dr.stats.DiscreteStatistics;
/**
* @author Jennifer Tom
* Based on S. X. Chen. Probability density function estimation using gamma kernels.
* Annals of the Institute of Statistical Mathematics, 52(3):471-480, 2000.
* Use to create KDE for positive valued functions
* Assumes limits are (0, inf)
* Must provide with a bandwidth, or defaults to Scott's Rule
* Univariate distribution only
*/
public class GammaKDEDistribution extends KernelDensityEstimatorDistribution {
public GammaKDEDistribution(Double[] sample) {
this(sample, null);
}
public GammaKDEDistribution(Double[] sample, Double bandWidth) {
super(sample, 0.0, Double.POSITIVE_INFINITY, bandWidth);
}
protected void processBounds(Double lowerBound, Double upperBound) {
if (lowerBound > DiscreteStatistics.min(sample)) {
throw new RuntimeException("Sample min out of bounds. Gamma kernel for use with positive data only: " + DiscreteStatistics.min(sample));
} else if (upperBound < DiscreteStatistics.max(sample)) {
throw new RuntimeException("Sample max out of bounds" + DiscreteStatistics.max(sample));
}
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
protected void setBandWidth(Double bandWidth) {
if (bandWidth == null) {
double sigma = DiscreteStatistics.stdev(sample);
//Scott's rule (Hardle, 2004, Nonparametric and Semiparameteric Models)
this.bandWidth = sigma * Math.pow(N, -0.2);
} else
this.bandWidth = bandWidth;
}
protected double evaluateKernel(double x) {
double shape;
double scale;
if (x >= 2 * bandWidth) {
shape = x / bandWidth;
} else {
shape = .25 * Math.pow(x / bandWidth, 2) + 1;
}
scale = bandWidth;
double pdf = 0;
for (int i = 0; i < N; i++) {
pdf +=
Math.pow(sample[i], shape - 1) * Math.exp(-sample[i] / scale) / (Math.pow(scale, shape) * gamma(shape));
}
return pdf / N;
}
private double gamma(double value) {
return cern.jet.stat.Gamma.gamma(value);
}
// private double sampleMean() {return DiscreteStatistics.mean(sample);}
// public static void main(String[] args) {
// String fileName = "/Users/jen/School/Programs/BEAST/kdeTest/simulUExp.txt";
// //String fileName = "/Users/jen/School/Programs/BEAST/kdeTest/simulUNorm.txt";
// double[] values = null; //vector of the training set
// try{
// BufferedReader br = new BufferedReader(new FileReader(fileName));
// StringBuilder AllDataSb = new StringBuilder();
// String s;
// String myLineSeparator = "\r";
// while (( s = br.readLine()) != null){
// AllDataSb.append(s);
// AllDataSb.append(myLineSeparator);
// }
// //convert from stringbuilder to string
// String AllDataS = AllDataSb.toString();
// String[] result = AllDataS.split("\t|\r|,");
//
// //convert string to double
// values = new double[result.length];
// for (int i = 0; i < result.length; i++) {values[i] = Double.parseDouble(result[i]);}
//
// } //close try
// catch(Exception e){
// System.out.println(e.getMessage());
// System.exit(-1);
// }
//
//
// GammaKDEDistribution kde;
//
//
// //expecting 2.02177 -> .073; .4046729 -> 1.0257; 0.1502078 -> 1.4021
// //normal-reference bandwidth 0.1939
// kde = new GammaKDEDistribution(values, null);
// System.err.println("prediction: at 2.02: "+kde.pdf(2.02177)+" at 0.405: "+kde.pdf(0.4046729)+" at 0.15: "+kde.pdf(0.1502078));
// System.err.println("sm: "+kde.sampleMean());
// }
}