![JAR search and dependency download from the Maven repository](/logo.png)
smile.stat.distribution.ExponentialDistribution Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2010-2020 Haifeng Li. All rights reserved.
*
* Smile 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 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Smile. If not, see .
******************************************************************************/
package smile.stat.distribution;
import smile.math.MathEx;
/**
* An exponential distribution describes the times between events in a Poisson
* process, in which events occur continuously and independently at a constant
* average rate. Exponential variables can also be used to model situations
* where certain events occur with a constant probability per unit length,
* such as the distance between mutations on a DNA strand. In real world
* scenarios, the assumption of a constant rate is rarely satisfied. But if
* we focus on a time interval during which the rate is roughly constant, the
* exponential distribution can be used as a good approximate model.
*
* The exponential distribution may be viewed as a continuous counterpart of
* the geometric distribution, which describes the number of Bernoulli trials
* necessary for a discrete process to change state. In contrast,
* the exponential distribution describes the time for a continuous process to
* change state.
*
* The probability density function of an exponential distribution is
* f(x; λ) = λe-λx for x ≥ 0. The cumulative
* distribution function is given by F(x; λ) = 1 - e-λ x
* for x ≥ 0. An important property of the exponential distribution is that
* it is memoryless. This means that if a random variable T is exponentially
* distributed, its conditional probability obeys
* Pr(T > s + t | T > s) = Pr(T > t) for all s, t ≥ 0.
*
* In queuing theory, the service times of agents in a system are often modeled as
* exponentially distributed variables. Reliability theory and reliability
* engineering also make extensive use of the exponential distribution. Because
* of the memoryless property of this distribution, it is well-suited to model
* the constant hazard rate portion of the bathtub curve used in reliability
* theory. The exponential distribution is however not appropriate to model
* the overall lifetime of organisms or technical devices, because the "failure
* rates" here are not constant: more failures occur for very young and for
* very old systems.
*
* @author Haifeng Li
*/
public class ExponentialDistribution extends AbstractDistribution implements ExponentialFamily {
private static final long serialVersionUID = 2L;
/** The rate parameter. */
public final double lambda;
/**
* Constructor.
* @param lambda rate parameter.
*/
public ExponentialDistribution(double lambda) {
if (lambda <= 0) {
throw new IllegalArgumentException("Invalid lambda: " + lambda);
}
this.lambda = lambda;
}
/**
* Estimates the distribution parameters by MLE.
*/
public static ExponentialDistribution fit(double[] data) {
for (int i = 0; i < data.length; i++) {
if (data[i] < 0) {
throw new IllegalArgumentException("Samples contain negative values.");
}
}
double mean = MathEx.mean(data);
if (mean == 0) {
throw new IllegalArgumentException("Samples are all zeros.");
}
double lambda = 1 / mean;
return new ExponentialDistribution(lambda);
}
@Override
public int length() {
return 1;
}
@Override
public double mean() {
return 1 / lambda;
}
@Override
public double variance() {
return 1 / (lambda * lambda);
}
@Override
public double sd() {
return 1 / lambda;
}
@Override
public double entropy() {
return 1 - Math.log(lambda);
}
@Override
public String toString() {
return String.format("Exponential Distribution(%.4f)", lambda);
}
@Override
public double rand() {
return -1 / lambda * Math.log(MathEx.random());
}
@Override
public double p(double x) {
if (x < 0) {
return 0.0;
} else {
return lambda * Math.exp(-lambda * x);
}
}
@Override
public double logp(double x) {
if (x < 0) {
return Double.NEGATIVE_INFINITY;
} else {
return Math.log(lambda) - lambda * x;
}
}
@Override
public double cdf(double x) {
if (x < 0) {
return 0.0;
} else {
return 1 - Math.exp(-lambda * x);
}
}
@Override
public double quantile(double p) {
if (p < 0.0 || p > 1.0) {
throw new IllegalArgumentException("Invalid p: " + p);
}
return -Math.log(1 - p) / lambda;
}
@Override
public Mixture.Component M(double[] x, double[] posteriori) {
double alpha = 0.0;
double mean = 0.0;
for (int i = 0; i < x.length; i++) {
alpha += posteriori[i];
mean += x[i] * posteriori[i];
}
mean /= alpha;
return new Mixture.Component(alpha, new ExponentialDistribution(1 / mean));
}
}