gov.sandia.cognition.statistics.distribution.LogNormalDistribution Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: LogNormalDistribution.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright November 13, 2007, Sandia Corporation. Under the terms of Contract
* DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
* or on behalf of the U.S. Government. Export of this program may require a
* license from the United States Government. See CopyrightHistory.txt for
* complete details.
*
*/
package gov.sandia.cognition.statistics.distribution;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.math.UnivariateStatisticsUtil;
import gov.sandia.cognition.math.matrix.VectorFactory;
import gov.sandia.cognition.math.matrix.Vector;
import gov.sandia.cognition.statistics.AbstractClosedFormSmoothUnivariateDistribution;
import gov.sandia.cognition.statistics.DistributionEstimator;
import gov.sandia.cognition.statistics.DistributionWeightedEstimator;
import gov.sandia.cognition.statistics.EstimableDistribution;
import gov.sandia.cognition.statistics.UnivariateProbabilityDensityFunction;
import gov.sandia.cognition.statistics.SmoothCumulativeDistributionFunction;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import gov.sandia.cognition.util.DefaultWeightedValue;
import gov.sandia.cognition.util.Pair;
import gov.sandia.cognition.util.WeightedValue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;
/**
* Log-Normal distribution PDF and CDF implementations. The Log-Normal
* distribution is related to a UnivariateGaussian where the natural logarithm
* of the random variable is normally distributed. This turns up in
* application areas that are the product of some random variables, where
* each random variable is i.i.d. and normally distributed. Stock market
* returns are the classic example of a Log-Normal distribution.
*
* @author Kevin R. Dixon
* @since 2.0
*
*/
@PublicationReference(
author="Wikipedia",
title="Log-normal distribution",
type=PublicationType.WebPage,
year=2009,
url="http://en.wikipedia.org/wiki/Log-normal_distribution"
)
public class LogNormalDistribution
extends AbstractClosedFormSmoothUnivariateDistribution
implements EstimableDistribution
{
/**
* Default log normal mean, {@value}.
*/
public static final double DEFAULT_LOG_NORMAL_MEAN = 0.0;
/**
* Default log normal variance, {@value}.
*/
public static final double DEFAULT_LOG_NORMAL_VARIANCE = 1.0;
/**
* Constant value of Math.sqrt(2*Math.PI)
*/
public static final double SQRT2PI = Math.sqrt( 2.0 * Math.PI );
/**
* Mean of the underlying distribution, (-infinity,+infinity)
*/
private double logNormalMean;
/**
* Variance of the underlying distribution, (0,infinity)
*/
private double logNormalVariance;
/**
* Default constructor.
*/
public LogNormalDistribution()
{
this( DEFAULT_LOG_NORMAL_MEAN, DEFAULT_LOG_NORMAL_VARIANCE );
}
/**
* Creates a new instance of LogNormalDistribution
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
*/
public LogNormalDistribution(
final double logNormalMean,
final double logNormalVariance )
{
super();
this.setLogNormalMean( logNormalMean );
this.setLogNormalVariance( logNormalVariance );
}
/**
* Copy Constructor
* @param other LogNormalDistribution to copy
*/
public LogNormalDistribution(
final LogNormalDistribution other )
{
this( other.getLogNormalMean(), other.getLogNormalVariance() );
}
/**
* Returns a 2-dimensional Vector with ( logNormalMean logNormalVariance )
* @return
* 2-dimensional Vector with ( logNormalMean logNormalVariance )
*/
@Override
public Vector convertToVector()
{
return VectorFactory.getDefault().copyValues(
this.getLogNormalMean(), this.getLogNormalVariance() );
}
/**
* Sets the parameters of the distribution from a
* 2-dimensional Vector with ( logNormalMean logNormalVariance )
* @param parameters
* 2-dimensional Vector with ( logNormalMean logNormalVariance )
*/
@Override
public void convertFromVector(
final Vector parameters )
{
if( parameters.getDimensionality() != 2 )
{
throw new IllegalArgumentException(
"Parameters must be dimension 2" );
}
this.setLogNormalMean( parameters.getElement( 0 ) );
this.setLogNormalVariance( parameters.getElement( 1 ) );
}
/**
* Getter for logNormalMean
* @return
* Mean of the underlying distribution, (-infinity,+infinity)
*/
public double getLogNormalMean()
{
return this.logNormalMean;
}
/**
* Setter for logNormalMean
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
*/
public void setLogNormalMean(
final double logNormalMean )
{
this.logNormalMean = logNormalMean;
}
/**
* Getter for logNormalVariance
* @return
* Variance of the underlying distribution, (0,infinity)
*/
public double getLogNormalVariance()
{
return this.logNormalVariance;
}
/**
* Setter for logNormalVariance
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
*/
public void setLogNormalVariance(
final double logNormalVariance )
{
if( logNormalVariance <= 0.0 )
{
throw new IllegalArgumentException(
"logNormalVariance must be > 0.0" );
}
this.logNormalVariance = logNormalVariance;
}
@Override
public double getMeanAsDouble()
{
double exp = this.getLogNormalMean() + 0.5 * this.getLogNormalVariance();
return Math.exp( exp );
}
@Override
public double getVariance()
{
double exp1 = this.getLogNormalVariance();
double exp2 = 2.0 * this.getLogNormalMean() + this.getLogNormalVariance();
// (Math.exp(exp1)-1)*Math.exp(exp2)
return (Math.expm1( exp1 ) * Math.exp( exp2 ));
}
@Override
public double sampleAsDouble(
final Random random)
{
final double std = Math.sqrt(this.logNormalVariance);
double normal = random.nextGaussian();
double exponent = this.logNormalMean + std * normal;
return Math.exp(exponent);
}
@Override
public void sampleInto(
final Random random,
final double[] output,
final int start,
final int length)
{
final double std = Math.sqrt(this.logNormalVariance);
final int end = start + length;
for (int i = start; i < end; i++)
{
double normal = random.nextGaussian();
double exponent = this.logNormalMean + std * normal;
output[i] = Math.exp(exponent);
}
}
@Override
public LogNormalDistribution.CDF getCDF()
{
return new LogNormalDistribution.CDF( this );
}
@Override
public LogNormalDistribution.PDF getProbabilityFunction()
{
return new LogNormalDistribution.PDF( this );
}
@Override
public String toString()
{
return "Log-Mean: " + this.logNormalMean + " Log-Variance: " + this.logNormalVariance;
}
@Override
public Double getMinSupport()
{
return 0.0;
}
@Override
public Double getMaxSupport()
{
return Double.POSITIVE_INFINITY;
}
@Override
public LogNormalDistribution.MaximumLikelihoodEstimator getEstimator()
{
return new LogNormalDistribution.MaximumLikelihoodEstimator();
}
/**
* PDF of a Log-normal distribution
*/
public static class PDF
extends LogNormalDistribution
implements UnivariateProbabilityDensityFunction
{
/**
* Default constructor.
*/
public PDF()
{
super();
}
/**
* Creates a new instance of LogNormalDistribution
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
*/
public PDF(
final double logNormalMean,
final double logNormalVariance )
{
super( logNormalMean, logNormalVariance );
}
/**
* Copy Constructor
* @param other LogNormalDistribution to copy
*/
public PDF(
final LogNormalDistribution other )
{
super( other );
}
@Override
public Double evaluate(
final Double input )
{
return this.evaluate( input.doubleValue() );
}
@Override
public double evaluateAsDouble(
final Double input)
{
return this.evaluate(input.doubleValue());
}
@Override
public double evaluate(
final double input )
{
return evaluate(
input, this.getLogNormalMean(), this.getLogNormalVariance() );
}
/**
* Evaluates the Log-Normal PDF for the given input and parameters
* logNormalMean, logNormalVariance
* @param input
* Input about which to evaluate the PDF
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
* @return
* pdf(input|mean,variance)
*/
public static double evaluate(
final double input,
final double logNormalMean,
final double logNormalVariance )
{
if (input <= 0)
{
return 0.0;
}
double delta = Math.log( input ) - logNormalMean;
double exp = Math.exp( delta * delta / (-2.0 * logNormalVariance) );
double denom = SQRT2PI * input * Math.sqrt( logNormalVariance );
return exp / denom;
}
@Override
public double logEvaluate(
final Double input)
{
return this.logEvaluate((double) input);
}
@Override
public double logEvaluate(
final double input)
{
return logEvaluate(input, this.getLogNormalMean(), this.getLogNormalVariance());
}
/**
* Computes the natural logarithm of the PDF.
* @param input
* Inpu to consider.
* @param logNormalMean
* Log normal mean.
* @param logNormalVariance
* Log normal variance.
* @return
* Natural logarithm of the PDF.
*/
public static double logEvaluate(
final double input,
final double logNormalMean,
final double logNormalVariance )
{
final double logInput = Math.log(input);
final double delta = logInput - logNormalMean;
final double exponent = delta*delta / (-2.0*logNormalVariance);
final double coefficient = -0.5 * Math.log(UnivariateGaussian.PI2*logNormalVariance);
return exponent + coefficient - logInput;
}
@Override
public LogNormalDistribution.PDF getProbabilityFunction()
{
return this;
}
}
/**
* CDF of the Log-Normal Distribution
*/
public static class CDF
extends LogNormalDistribution
implements SmoothCumulativeDistributionFunction
{
/**
* Default constructor.
*/
public CDF()
{
super();
}
/**
* Creates a new instance of LogNormalDistribution
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
*/
public CDF(
final double logNormalMean,
final double logNormalVariance )
{
super( logNormalMean, logNormalVariance );
}
/**
* Copy Constructor
* @param other LogNormalDistribution to copy
*/
public CDF(
final LogNormalDistribution other )
{
super( other );
}
@Override
public double evaluate(
final double input )
{
return evaluate(
input, this.getLogNormalMean(), this.getLogNormalVariance() );
}
/**
* Evaluates the Log-Normal CDF for the given input and parameters
* @param x
* Input about which to compute the CDF
* @param logNormalMean
* Mean of the underlying distribution, (-infinity,+infinity)
* @param logNormalVariance
* Variance of the underlying distribution, (0,infinity)
* @return
* CDF of the distribution
*/
public static double evaluate(
final double x,
final double logNormalMean,
final double logNormalVariance )
{
if (x <= 0.0)
{
return 0.0;
}
double num = Math.log( x ) - logNormalMean;
double denom = Math.sqrt( 2 * logNormalVariance );
double erf = UnivariateGaussian.ErrorFunction.INSTANCE.evaluate( num / denom );
return 0.5 * (1 + erf);
}
@Override
public Double evaluate(
final Double input )
{
return this.evaluate( input.doubleValue() );
}
@Override
public double evaluateAsDouble(
final Double input)
{
return this.evaluate(input.doubleValue());
}
@Override
public LogNormalDistribution.CDF getCDF()
{
return this;
}
@Override
public LogNormalDistribution.PDF getDerivative()
{
return this.getProbabilityFunction();
}
@Override
public Double differentiate(
final Double input)
{
return this.getDerivative().evaluate(input);
}
}
/**
* Maximum Likelihood Estimator of a log-normal distribution.
*/
public static class MaximumLikelihoodEstimator
extends AbstractCloneableSerializable
implements DistributionEstimator
{
/**
* Default constructor
*/
public MaximumLikelihoodEstimator()
{
}
@Override
public LogNormalDistribution.PDF learn(
final Collection extends Double> data)
{
ArrayList logdata = new ArrayList( data.size() );
for( Double value : data )
{
logdata.add( Math.log(value) );
}
Pair pair =
UnivariateStatisticsUtil.computeMeanAndVariance( logdata );
return new LogNormalDistribution.PDF(
pair.getFirst(), pair.getSecond() );
}
}
/**
* Maximum Likelihood Estimator from weighted data
*/
public static class WeightedMaximumLikelihoodEstimator
extends AbstractCloneableSerializable
implements DistributionWeightedEstimator
{
/**
* Default constructor
*/
public WeightedMaximumLikelihoodEstimator()
{
}
@Override
public LogNormalDistribution.PDF learn(
final Collection extends WeightedValue extends Double>> data )
{
ArrayList> logdata =
new ArrayList>( data.size() );
for( WeightedValue extends Number> value : data )
{
final double x = value.getValue().doubleValue();
double logx;
double weight;
if( x > 0.0 )
{
logx = Math.log(x);
weight = value.getWeight();
}
else
{
logx = Double.NEGATIVE_INFINITY;
weight = 0.0;
}
logdata.add( new DefaultWeightedValue( logx, weight ) );
}
Pair pair =
UnivariateStatisticsUtil.computeWeightedMeanAndVariance(logdata);
return new LogNormalDistribution.PDF(
pair.getFirst(), pair.getSecond() );
}
}
}