smile.stat.distribution.ShiftedGeometricDistribution Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (c) 2010 Haifeng Li
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package smile.stat.distribution;
import smile.math.Math;
/**
* The "shifted" geometric distribution is a discrete probability distribution of the
* number of failures before the first success, supported on the set
* {0, 1, 2, 3, …}.
* If the probability of success on each trial is p, then the probability that
* the k-th trial (out of k trials) is the first success is
* Pr(X = k) = (1 - p)k p.
* @see GeometricDistribution
*
* @author Haifeng Li
*/
public class ShiftedGeometricDistribution extends DiscreteDistribution implements DiscreteExponentialFamily {
private double p;
private double entropy;
/**
* The exponential distribution to generate Geometric distributed
* random number.
*/
ExponentialDistribution expDist;
/**
* Constructor.
* @param p the probability of success.
*/
public ShiftedGeometricDistribution(double p) {
if (p <= 0 || p > 1) {
throw new IllegalArgumentException("Invalid p: " + p);
}
this.p = p;
entropy = (-p * Math.log2(p) - (1 - p) * Math.log2(1 - p)) / p;
}
/**
* Constructor. Parameter will be estimated from the data by MLE.
*/
public ShiftedGeometricDistribution(int[] data) {
double sum = 0.0;
for (int x : data) {
if (x < 0) {
throw new IllegalArgumentException("Invalid value " + x);
}
sum += x + 1;
}
p = data.length / sum;
entropy = (-p * Math.log2(p) - (1 - p) * Math.log2(1 - p)) / p;
}
/**
* Returns the probability of success.
*/
public double getProb() {
return p;
}
@Override
public int npara() {
return 1;
}
@Override
public double mean() {
return 1 / p;
}
@Override
public double var() {
return (1 - p) / (p * p);
}
@Override
public double sd() {
return Math.sqrt(1 - p) / p;
}
@Override
public double entropy() {
return entropy;
}
@Override
public String toString() {
return String.format("Shifted Geometric Distribution(%.4f)", p);
}
@Override
public double rand() {
if (expDist == null) {
double lambda = -Math.log(1 - p);
expDist = new ExponentialDistribution(lambda);
}
return Math.floor(expDist.rand());
}
@Override
public double p(int k) {
if (k <= 0) {
return 0.0;
} else {
return Math.pow(1 - p, k - 1) * p;
}
}
@Override
public double logp(int k) {
if (k <= 0) {
return Double.NEGATIVE_INFINITY;
} else {
return (k - 1) * Math.log(1 - p) + Math.log(p);
}
}
@Override
public double cdf(double k) {
if (k < 0) {
return 0.0;
} else {
return 1 - Math.pow(1 - p, k);
}
}
@Override
public double quantile(double p) {
if (p < 0.0 || p > 1.0) {
throw new IllegalArgumentException("Invalid p: " + p);
}
int n = (int) Math.max(Math.sqrt(1 / this.p), 5.0);
int nl, nu, inc = 1;
if (p < cdf(n)) {
do {
n = Math.max(n - inc, 0);
inc *= 2;
} while (p < cdf(n));
nl = n;
nu = n + inc / 2;
} else {
do {
n += inc;
inc *= 2;
} while (p > cdf(n));
nu = n;
nl = n - inc / 2;
}
return quantile(p, nl, nu);
}
@Override
public DiscreteMixture.Component M(int[] 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;
DiscreteMixture.Component c = new DiscreteMixture.Component();
c.priori = alpha;
c.distribution = new GeometricDistribution(1 / (1 + mean));
return c;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy