package dist; import java.io.Serializable; import java.util.Arrays; import shared.Copyable; import shared.DataSet; import shared.Instance; import util.ABAGAILArrays; import util.linalg.Vector; /** * A probabilitiy function for representing single discrete * output values * @author Andrew Guillory gtg008g@mail.gatech.edu * @version 1.0 */ public class DiscreteDistribution extends AbstractDistribution implements Serializable, Copyable { /** * The array of probabilities */ private double[] probabilities; /** * The prior probabilities */ private double[] prior; /** * The cummulatives */ private double[] cummulatives; /** * The continuity parameter */ private double m; /** * Make a new single discrete output * that models the given probabilities * @param probabilities array of probabilitites * such that the probabilities of output i * is probabilitites[i] * @param m the continuity parameter */ public DiscreteDistribution(Vector vector) { this.m = vector.size(); this.prior = new double[vector.size()]; Arrays.fill(prior, 1.0/vector.size()); probabilities = new double[vector.size()]; for (int i = 0; i < vector.size(); i++) { probabilities[i] = vector.get(i); } cummulatives = null; } /** * Make a new single discrete output * that models the given probabilities * @param probabilities array of probabilitites * such that the probabilities of output i * is probabilitites[i] * @param m the continuity parameter */ public DiscreteDistribution(double[] probabilities) { this.probabilities = probabilities; this.m = probabilities.length; this.prior = new double[probabilities.length]; Arrays.fill(prior, 1.0/probabilities.length); cummulatives = null; } /** * Set the probabilities * @param probabilities the probabilities */ public void setProbabilities(double[] probabilities) { this.probabilities = probabilities; cummulatives = null; } /** * Get the probabilities * @return the probailities */ public double[] getProbabilities() { return probabilities; } /** * Get the probability of i * @param i the discrete value to get the probability of * @return the probability of i */ public double p(Instance i) { return probabilities[i.getDiscrete()]; } /** * Generate a discrete value consistent with the distribution * @return the discrete value */ public Instance sample(Instance ignored) { if (cummulatives == null) { calculateCummulatives(); } double rand = random.nextDouble(); return new Instance(ABAGAILArrays.search(cummulatives, rand)); } /** * Recalculate the cummulativies */ private void calculateCummulatives() { cummulatives = new double[probabilities.length]; cummulatives[0] = probabilities[0]; for (int i = 1; i < cummulatives.length; i++) { cummulatives[i] = cummulatives[i-1] + probabilities[i]; } } /** * Generate the most likely value * @return the value */ public Instance mode(Instance ignored) { int argMax = 0; for (int i = 1; i < probabilities.length; i++) { if (probabilities[i] > probabilities[argMax]) { argMax = i; } } return new Instance(argMax); } /** * Reestimage based on the given data set * @param observations the observations */ public void estimate(DataSet observations) { double weightSum = 0; for (int i = 0; i < probabilities.length; i++) { probabilities[i] = 0; } for (int i = 0; i < observations.size(); i++) { Instance cur = observations.get(i); weightSum += cur.getWeight(); probabilities[cur.getDiscrete()] += cur.getWeight(); } for (int i = 0; i < probabilities.length; i++) { probabilities[i] = (probabilities[i] + m * prior[i]) / (weightSum + m); } cummulatives = null; } /** * Get the range of values represented * @return the range */ public int getRange() { return probabilities.length; } /** * Get the m value * @return the m value */ public double getM() { return m; } /** * Set the m value * @param d the new m value */ public void setM(double d) { m = d; } /** * Set the prior probability * @param priors the prior */ public void setPrior(double[] priors) { this.prior = priors; } /** * Get the prior probability * @return the prior probability */ public double[] getPrior() { return prior; } /** * @see java.lang.Object#toString() */ public String toString() { return ABAGAILArrays.toString(probabilities); } /** * @see shared.Copyable#copy() */ public Copyable copy() { double[] copyProbabilities = new double[probabilities.length]; for (int i = 0; i < copyProbabilities.length; i++) { copyProbabilities[i] = probabilities[i]; } DiscreteDistribution copy = new DiscreteDistribution(copyProbabilities); copy.setM(m); copy.setPrior(prior); return copy; } /** * Make a new single discrete output * that models values [0, 1, 2, ..., range - 1] * @param range the upper range of the output */ public static DiscreteDistribution random(int range) { double[] probabilities = new double[range]; // random intial values double sum = 0; for (int i = 0; i < probabilities.length; i++) { probabilities[i] = random.nextDouble(); sum += probabilities[i]; } for (int i = 0; i < probabilities.length; i++) { probabilities[i] /= sum; } return new DiscreteDistribution(probabilities); } /** * Make a new single discrete output * that models values [0, 1, 2, ..., range - 1] * @param range the upper range of the output */ public static DiscreteDistribution uniform(int range) { double[] probabilities = new double[range]; Arrays.fill(probabilities, 1.0/probabilities.length); return new DiscreteDistribution(probabilities); } }