All Downloads are FREE. Search and download functionalities are using the official Maven repository.

smile.stat.distribution.LogNormalDistribution Maven / Gradle / Ivy

There is a newer version: 2.6.0
Show newest version
/******************************************************************************
 *                   Confidential Proprietary                                 *
 *         (c) Copyright Haifeng Li 2011, All Rights Reserved                 *
 ******************************************************************************/
package smile.stat.distribution;

import smile.math.special.Erf;
import smile.math.Math;

/**
 * A log-normal distribution is a probability distribution of a random variable
 * whose logarithm is normally distributed. The log-normal distribution is the single-tailed probability distribution
 * of any random variable whose logarithm is normally distributed. If X is a
 * random variable with a normal distribution, then Y = exp(X) has a log-normal
 * distribution; likewise, if Y is log-normally distributed, then log(Y) is
 * normally distributed.
 * A variable might be modeled as log-normal if it can be thought of as
 * the multiplicative product of many independent random variables each of
 * which is positive.
 *
 * @author Haifeng Li
 */
public class LogNormalDistribution extends AbstractDistribution {
    private double mu;
    private double sigma;
    private double mean;
    private double var;
    private double entropy;
    private GaussianDistribution gaussian;

    /**
     * Constructor.
     */
    public LogNormalDistribution(double mu, double sigma) {
        if (sigma <= 0.0) {
            throw new IllegalArgumentException("Invalid sigma: " + sigma);
        }
        this.mu = mu;
        this.sigma = sigma;

        mean = Math.exp(mu + sigma * sigma / 2);
        var = (Math.exp(mu * mu) - 1) * Math.exp(2 * mu + sigma * sigma);
        entropy = 0.5 + 0.5 * Math.log(2 * Math.PI * sigma * sigma) + mu;
    }

    /**
     * Constructor. Parameter will be estimated from the data by MLE.
     */
    public LogNormalDistribution(double[] data) {
        double[] x = new double[data.length];
        for (int i = 0; i < x.length; i++) {
            if (data[i] <= 0.0) {
                throw new IllegalArgumentException("Invalid input data: " + data[i]);
            }

            x[i] = Math.log(data[i]);
        }

        this.mu = Math.mean(x);
        this.sigma = Math.sd(x);

        mean = Math.exp(mu + sigma * sigma / 2);
        var = (Math.exp(mu * mu) - 1) * Math.exp(2 * mu + sigma * sigma);
        entropy = 0.5 + 0.5 * Math.log(2 * Math.PI * sigma * sigma) + mu;
    }

    /**
     * Returns the parameter mu, which is the mean of normal distribution log(X).
     */
    public double getMu() {
        return mu;
    }

    /**
     * Returns the parameter sigma, which is the standard deviation of normal distribution log(X).
     */
    public double getSigma() {
        return sigma;
    }

    @Override
    public int npara() {
        return 2;
    }

    @Override
    public double mean() {
        return mean;
    }

    @Override
    public double var() {
        return var;
    }

    @Override
    public double sd() {
        return Math.sqrt(var);
    }

    @Override
    public double entropy() {
        return entropy;
    }

    @Override
    public String toString() {
        return String.format("Log Normal Distribution(%.4f, %.4f)", mu, sigma);
    }

    @Override
    public double rand() {
        if (gaussian == null) {
            gaussian = new GaussianDistribution(mu, sigma);
        }

        return Math.exp(gaussian.rand());
    }

    @Override
    public double p(double x) {
        if (x < 0.0) {
            throw new IllegalArgumentException("Invalid x: " + x);
        }

        if (x == 0.0) {
            return 0.0;
        }

        double t = (Math.log(x) - mu) / sigma;
        return (0.398942280401432678 / (sigma * x)) * Math.exp(-0.5 * t * t);
    }

    @Override
    public double logp(double x) {
        return Math.log(p(x));
    }

    @Override
    public double cdf(double x) {
        if (x < 0.0) {
            throw new IllegalArgumentException("Invalid x: " + x);
        }

        if (x == 0.0) {
            return 0.;
        }

        return 0.5 * Erf.erfc(-0.707106781186547524 * (Math.log(x) - mu) / sigma);
    }

    @Override
    public double quantile(double p) {
        if (p < 0.0 || p > 1.0) {
            throw new IllegalArgumentException("Invalid p: " + p);
        }

        return Math.exp(-1.41421356237309505 * sigma * Erf.inverfc(2.0 * p) + mu);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy