
smile.stat.distribution.LogNormalDistribution Maven / Gradle / Ivy
/*
* Copyright (c) 2010-2021 Haifeng Li. All rights reserved.
*
* Smile is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Smile 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Smile. If not, see .
*/
package smile.stat.distribution;
import smile.math.MathEx;
import smile.math.special.Erf;
import java.io.Serial;
/**
* 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 implements Distribution {
@Serial
private static final long serialVersionUID = 2L;
/** The mean of normal distribution. */
public final double mu;
/** The standard deviation of normal distribution. */
public final double sigma;
/** The mean. */
public final double mean;
/** The variance. */
private final double variance;
/** Shannon entropy. */
private final double entropy;
/** The corresponding Gaussian distribution. */
private GaussianDistribution gaussian;
/**
* Constructor.
* @param mu the mean of normal distribution.
* @param sigma the standard deviation of normal distribution.
*/
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);
variance = (Math.exp(mu * mu) - 1) * Math.exp(2 * mu + sigma * sigma);
entropy = 0.5 + 0.5 * Math.log(2 * Math.PI * sigma * sigma) + mu;
}
/**
* Estimates the distribution parameters by MLE.
* @param data the training data.
* @return the distribution.
*/
public static LogNormalDistribution fit(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]);
}
double mu = MathEx.mean(x);
double sigma = MathEx.sd(x);
return new LogNormalDistribution(mu, sigma);
}
@Override
public int length() {
return 2;
}
@Override
public double mean() {
return mean;
}
@Override
public double variance() {
return variance;
}
@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 - 2025 Weber Informatics LLC | Privacy Policy