gonum.org/v1/gonum@v0.14.0/stat/distuv/poisson.go (about)

     1  // Copyright ©2017 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package distuv
     6  
     7  import (
     8  	"math"
     9  
    10  	"golang.org/x/exp/rand"
    11  
    12  	"gonum.org/v1/gonum/mathext"
    13  )
    14  
    15  // Poisson implements the Poisson distribution, a discrete probability distribution
    16  // that expresses the probability of a given number of events occurring in a fixed
    17  // interval.
    18  // The poisson distribution has density function:
    19  //
    20  //	f(k) = λ^k / k! e^(-λ)
    21  //
    22  // For more information, see https://en.wikipedia.org/wiki/Poisson_distribution.
    23  type Poisson struct {
    24  	// Lambda is the average number of events in an interval.
    25  	// Lambda must be greater than 0.
    26  	Lambda float64
    27  
    28  	Src rand.Source
    29  }
    30  
    31  // CDF computes the value of the cumulative distribution function at x.
    32  func (p Poisson) CDF(x float64) float64 {
    33  	if x < 0 {
    34  		return 0
    35  	}
    36  	return mathext.GammaIncRegComp(math.Floor(x+1), p.Lambda)
    37  }
    38  
    39  // ExKurtosis returns the excess kurtosis of the distribution.
    40  func (p Poisson) ExKurtosis() float64 {
    41  	return 1 / p.Lambda
    42  }
    43  
    44  // LogProb computes the natural logarithm of the value of the probability
    45  // density function at x.
    46  func (p Poisson) LogProb(x float64) float64 {
    47  	if x < 0 || math.Floor(x) != x {
    48  		return math.Inf(-1)
    49  	}
    50  	lg, _ := math.Lgamma(math.Floor(x) + 1)
    51  	return x*math.Log(p.Lambda) - p.Lambda - lg
    52  }
    53  
    54  // Mean returns the mean of the probability distribution.
    55  func (p Poisson) Mean() float64 {
    56  	return p.Lambda
    57  }
    58  
    59  // NumParameters returns the number of parameters in the distribution.
    60  func (Poisson) NumParameters() int {
    61  	return 1
    62  }
    63  
    64  // Prob computes the value of the probability density function at x.
    65  func (p Poisson) Prob(x float64) float64 {
    66  	return math.Exp(p.LogProb(x))
    67  }
    68  
    69  // Rand returns a random sample drawn from the distribution.
    70  func (p Poisson) Rand() float64 {
    71  	// NUMERICAL RECIPES IN C: THE ART OF SCIENTIFIC COMPUTING (ISBN 0-521-43108-5)
    72  	// p. 294
    73  	// <http://www.aip.de/groups/soe/local/numres/bookcpdf/c7-3.pdf>
    74  
    75  	rnd := rand.ExpFloat64
    76  	var rng *rand.Rand
    77  	if p.Src != nil {
    78  		rng = rand.New(p.Src)
    79  		rnd = rng.ExpFloat64
    80  	}
    81  
    82  	if p.Lambda < 10.0 {
    83  		// Use direct method.
    84  		var em float64
    85  		t := 0.0
    86  		for {
    87  			t += rnd()
    88  			if t >= p.Lambda {
    89  				break
    90  			}
    91  			em++
    92  		}
    93  		return em
    94  	}
    95  	// Generate using:
    96  	//  W. Hörmann. "The transformed rejection method for generating Poisson
    97  	//  random variables." Insurance: Mathematics and Economics
    98  	//  12.1 (1993): 39-45.
    99  
   100  	// Algorithm PTRS
   101  	rnd = rand.Float64
   102  	if rng != nil {
   103  		rnd = rng.Float64
   104  	}
   105  	b := 0.931 + 2.53*math.Sqrt(p.Lambda)
   106  	a := -0.059 + 0.02483*b
   107  	invalpha := 1.1239 + 1.1328/(b-3.4)
   108  	vr := 0.9277 - 3.6224/(b-2)
   109  	for {
   110  		U := rnd() - 0.5
   111  		V := rnd()
   112  		us := 0.5 - math.Abs(U)
   113  		k := math.Floor((2*a/us+b)*U + p.Lambda + 0.43)
   114  		if us >= 0.07 && V <= vr {
   115  			return k
   116  		}
   117  		if k <= 0 || (us < 0.013 && V > us) {
   118  			continue
   119  		}
   120  		lg, _ := math.Lgamma(k + 1)
   121  		if math.Log(V*invalpha/(a/(us*us)+b)) <= k*math.Log(p.Lambda)-p.Lambda-lg {
   122  			return k
   123  		}
   124  	}
   125  }
   126  
   127  // Skewness returns the skewness of the distribution.
   128  func (p Poisson) Skewness() float64 {
   129  	return 1 / math.Sqrt(p.Lambda)
   130  }
   131  
   132  // StdDev returns the standard deviation of the probability distribution.
   133  func (p Poisson) StdDev() float64 {
   134  	return math.Sqrt(p.Variance())
   135  }
   136  
   137  // Survival returns the survival function (complementary CDF) at x.
   138  func (p Poisson) Survival(x float64) float64 {
   139  	return 1 - p.CDF(x)
   140  }
   141  
   142  // Variance returns the variance of the probability distribution.
   143  func (p Poisson) Variance() float64 {
   144  	return p.Lambda
   145  }