/* * GammaKDEDistribution.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.math.distributions; import dr.stats.DiscreteStatistics; import java.util.Random; /** * @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); } public static void main(String[] args) { long start = System.currentTimeMillis(); Random random = new Random(1234); Double[] samples = new Double[10000000]; for (int i = 0; i < samples.length; i++) { samples[i] = random.nextDouble(); } GammaKDEDistribution nKDE = new GammaKDEDistribution(samples); for (int i = 0; i < 100; i++) { nKDE.evaluateKernel(random.nextDouble()); } long end = System.currentTimeMillis(); System.out.println("Time: " + (end-start)); } // 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()); // } }