mirror of
https://github.com/gonum/gonum.git
synced 2025-10-28 09:31:40 +08:00
* stat/distuv: implement Poisson
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -38,6 +38,7 @@ Joseph Watson <jtwatson@linux-consulting.us>
|
||||
Josh Wilson <josh.craig.wilson@gmail.com>
|
||||
Julien Roland <juroland@gmail.com>
|
||||
Kent English <kent.english@gmail.com>
|
||||
Kevin C. Zimmerman <kevinczimmerman@gmail.com>
|
||||
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
|
||||
Leonid Kneller <recondite.matter@gmail.com>
|
||||
Lyron Winderbaum <lyron.winderbaum@student.adelaide.edu.au>
|
||||
|
||||
@@ -45,6 +45,7 @@ Joseph Watson <jtwatson@linux-consulting.us>
|
||||
Josh Wilson <josh.craig.wilson@gmail.com>
|
||||
Julien Roland <juroland@gmail.com>
|
||||
Kent English <kent.english@gmail.com>
|
||||
Kevin C. Zimmerman <kevinczimmerman@gmail.com>
|
||||
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
|
||||
Leonid Kneller <recondite.matter@gmail.com>
|
||||
Lyron Winderbaum <lyron.winderbaum@student.adelaide.edu.au>
|
||||
|
||||
109
stat/distuv/poisson.go
Normal file
109
stat/distuv/poisson.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright ©2017 The gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package distuv
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
|
||||
"gonum.org/v1/gonum/mathext"
|
||||
)
|
||||
|
||||
// Poisson implements the Poisson distribution, a discrete probability distribution
|
||||
// that expresses the probability of a given number of events occurring in a fixed
|
||||
// interval.
|
||||
// The poisson distribution has density function:
|
||||
// f(k) = λ^k / k! e^(-λ)
|
||||
// For more information, see https://en.wikipedia.org/wiki/Poisson_distribution.
|
||||
type Poisson struct {
|
||||
// Lambda is the average number of events in an interval.
|
||||
// Lambda must be greater than 0.
|
||||
Lambda float64
|
||||
|
||||
Source *rand.Rand
|
||||
}
|
||||
|
||||
// CDF computes the value of the cumulative distribution function at x.
|
||||
func (p Poisson) CDF(x float64) float64 {
|
||||
if x < 0 {
|
||||
return 0
|
||||
}
|
||||
return mathext.GammaIncComp(math.Floor(x+1), p.Lambda)
|
||||
}
|
||||
|
||||
// ExKurtosis returns the excess kurtosis of the distribution.
|
||||
func (p Poisson) ExKurtosis() float64 {
|
||||
return 1 / p.Lambda
|
||||
}
|
||||
|
||||
// LogProb computes the natural logarithm of the value of the probability
|
||||
// density function at x.
|
||||
func (p Poisson) LogProb(x float64) float64 {
|
||||
if x < 0 || math.Floor(x) != x {
|
||||
return math.Inf(-1)
|
||||
}
|
||||
lg, _ := math.Lgamma(math.Floor(x) + 1)
|
||||
return x*math.Log(p.Lambda) - p.Lambda - lg
|
||||
}
|
||||
|
||||
// Mean returns the mean of the probability distribution.
|
||||
func (p Poisson) Mean() float64 {
|
||||
return p.Lambda
|
||||
}
|
||||
|
||||
// NumParameters returns the number of parameters in the distribution.
|
||||
func (Poisson) NumParameters() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Prob computes the value of the probability density function at x.
|
||||
func (p Poisson) Prob(x float64) float64 {
|
||||
return math.Exp(p.LogProb(x))
|
||||
}
|
||||
|
||||
// Rand returns a random sample drawn from the distribution.
|
||||
func (p Poisson) Rand() float64 {
|
||||
// poisson generator based upon the multiplication of
|
||||
// uniform random variates.
|
||||
// see:
|
||||
// Non-Uniform Random Variate Generation,
|
||||
// Luc Devroye (p504)
|
||||
// http://www.eirene.de/Devroye.pdf
|
||||
x := 0.0
|
||||
prod := 1.0
|
||||
exp := math.Exp(-p.Lambda)
|
||||
rnd := rand.Float64
|
||||
if p.Source != nil {
|
||||
rnd = p.Source.Float64
|
||||
}
|
||||
|
||||
for {
|
||||
prod *= rnd()
|
||||
if prod <= exp {
|
||||
return x
|
||||
}
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
// Skewness returns the skewness of the distribution.
|
||||
func (p Poisson) Skewness() float64 {
|
||||
return 1 / math.Sqrt(p.Lambda)
|
||||
}
|
||||
|
||||
// StdDev returns the standard deviation of the probability distribution.
|
||||
func (p Poisson) StdDev() float64 {
|
||||
return math.Sqrt(p.Variance())
|
||||
}
|
||||
|
||||
// Survival returns the survival function (complementary CDF) at x.
|
||||
func (p Poisson) Survival(x float64) float64 {
|
||||
return 1 - p.CDF(x)
|
||||
}
|
||||
|
||||
// Variance returns the variance of the probability distribution.
|
||||
func (p Poisson) Variance() float64 {
|
||||
return p.Lambda
|
||||
}
|
||||
121
stat/distuv/poisson_test.go
Normal file
121
stat/distuv/poisson_test.go
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright ©2017 The gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package distuv
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"gonum.org/v1/gonum/floats"
|
||||
)
|
||||
|
||||
func TestPoissonProb(t *testing.T) {
|
||||
const tol = 1e-10
|
||||
for i, tt := range []struct {
|
||||
k float64
|
||||
lambda float64
|
||||
want float64
|
||||
}{
|
||||
{0, 1, 3.678794411714423e-01},
|
||||
{1, 1, 3.678794411714423e-01},
|
||||
{2, 1, 1.839397205857211e-01},
|
||||
{3, 1, 6.131324019524039e-02},
|
||||
{4, 1, 1.532831004881010e-02},
|
||||
{5, 1, 3.065662009762020e-03},
|
||||
{6, 1, 5.109436682936698e-04},
|
||||
{7, 1, 7.299195261338139e-05},
|
||||
{8, 1, 9.123994076672672e-06},
|
||||
{9, 1, 1.013777119630298e-06},
|
||||
|
||||
{0, 2.5, 8.208499862389880e-02},
|
||||
{1, 2.5, 2.052124965597470e-01},
|
||||
{2, 2.5, 2.565156206996838e-01},
|
||||
{3, 2.5, 2.137630172497365e-01},
|
||||
{4, 2.5, 1.336018857810853e-01},
|
||||
{5, 2.5, 6.680094289054267e-02},
|
||||
{6, 2.5, 2.783372620439277e-02},
|
||||
{7, 2.5, 9.940616501568845e-03},
|
||||
{8, 2.5, 3.106442656740263e-03},
|
||||
{9, 2.5, 8.629007379834082e-04},
|
||||
|
||||
{0.5, 2.5, 0},
|
||||
{1.5, 2.5, 0},
|
||||
{2.5, 2.5, 0},
|
||||
{3.5, 2.5, 0},
|
||||
{4.5, 2.5, 0},
|
||||
{5.5, 2.5, 0},
|
||||
{6.5, 2.5, 0},
|
||||
{7.5, 2.5, 0},
|
||||
{8.5, 2.5, 0},
|
||||
{9.5, 2.5, 0},
|
||||
} {
|
||||
p := Poisson{Lambda: tt.lambda}
|
||||
got := p.Prob(tt.k)
|
||||
if !floats.EqualWithinAbs(got, tt.want, tol) {
|
||||
t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoissonCDF(t *testing.T) {
|
||||
const tol = 1e-10
|
||||
for i, tt := range []struct {
|
||||
k float64
|
||||
lambda float64
|
||||
want float64
|
||||
}{
|
||||
{0, 1, 0.367879441171442},
|
||||
{1, 1, 0.735758882342885},
|
||||
{2, 1, 0.919698602928606},
|
||||
{3, 1, 0.981011843123846},
|
||||
{4, 1, 0.996340153172656},
|
||||
{5, 1, 0.999405815182418},
|
||||
{6, 1, 0.999916758850712},
|
||||
{7, 1, 0.999989750803325},
|
||||
{8, 1, 0.999998874797402},
|
||||
{9, 1, 0.999999888574522},
|
||||
|
||||
{0, 2.5, 0.082084998623899},
|
||||
{1, 2.5, 0.287297495183646},
|
||||
{2, 2.5, 0.543813115883329},
|
||||
{3, 2.5, 0.757576133133066},
|
||||
{4, 2.5, 0.891178018914151},
|
||||
{5, 2.5, 0.957978961804694},
|
||||
{6, 2.5, 0.985812688009087},
|
||||
{7, 2.5, 0.995753304510655},
|
||||
{8, 2.5, 0.998859747167396},
|
||||
{9, 2.5, 0.999722647905379},
|
||||
} {
|
||||
p := Poisson{Lambda: tt.lambda}
|
||||
got := p.CDF(tt.k)
|
||||
if !floats.EqualWithinAbs(got, tt.want, tol) {
|
||||
t.Errorf("test-%d: got=%e. want=%e\n", i, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPoisson(t *testing.T) {
|
||||
src := rand.New(rand.NewSource(1))
|
||||
for i, b := range []Poisson{
|
||||
{3, src},
|
||||
{1.5, src},
|
||||
{0.9, src},
|
||||
} {
|
||||
testPoisson(t, b, i)
|
||||
}
|
||||
}
|
||||
|
||||
func testPoisson(t *testing.T, p Poisson, i int) {
|
||||
tol := 1e-2
|
||||
const n = 1e6
|
||||
x := make([]float64, n)
|
||||
generateSamples(x, p)
|
||||
sort.Float64s(x)
|
||||
|
||||
checkMean(t, i, x, p, tol)
|
||||
checkVarAndStd(t, i, x, p, tol)
|
||||
checkExKurtosis(t, i, x, p, 7e-2)
|
||||
}
|
||||
Reference in New Issue
Block a user