github.com/gopherd/gonum@v0.0.4/stat/distuv/studentst.go (about) 1 // Copyright ©2016 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 "math/rand" 11 12 "github.com/gopherd/gonum/mathext" 13 ) 14 15 const logPi = 1.1447298858494001741 // http://oeis.org/A053510 16 17 // StudentsT implements the three-parameter Student's T distribution, a distribution 18 // over the real numbers. 19 // 20 // The Student's T distribution has density function 21 // Γ((ν+1)/2) / (sqrt(νπ) Γ(ν/2) σ) (1 + 1/ν * ((x-μ)/σ)^2)^(-(ν+1)/2) 22 // 23 // The Student's T distribution approaches the normal distribution as ν → ∞. 24 // 25 // For more information, see https://en.wikipedia.org/wiki/Student%27s_t-distribution, 26 // specifically https://en.wikipedia.org/wiki/Student%27s_t-distribution#Non-standardized_Student.27s_t-distribution . 27 // 28 // The standard Student's T distribution is with Mu = 0, and Sigma = 1. 29 type StudentsT struct { 30 // Mu is the location parameter of the distribution, and the mean of the 31 // distribution 32 Mu float64 33 34 // Sigma is the scale parameter of the distribution. It is related to the 35 // standard deviation by std = Sigma * sqrt(Nu/(Nu-2)) 36 Sigma float64 37 38 // Nu is the shape prameter of the distribution, representing the number of 39 // degrees of the distribution, and one less than the number of observations 40 // from a Normal distribution. 41 Nu float64 42 43 Src rand.Source 44 } 45 46 // CDF computes the value of the cumulative distribution function at x. 47 func (s StudentsT) CDF(x float64) float64 { 48 // transform to standard normal 49 y := (x - s.Mu) / s.Sigma 50 if y == 0 { 51 return 0.5 52 } 53 // For t > 0 54 // F(y) = 1 - 0.5 * I_t(y)(nu/2, 1/2) 55 // t(y) = nu/(y^2 + nu) 56 // and 1 - F(y) for t < 0 57 t := s.Nu / (y*y + s.Nu) 58 if y > 0 { 59 return 1 - 0.5*mathext.RegIncBeta(0.5*s.Nu, 0.5, t) 60 } 61 return 0.5 * mathext.RegIncBeta(s.Nu/2, 0.5, t) 62 } 63 64 // LogProb computes the natural logarithm of the value of the probability 65 // density function at x. 66 func (s StudentsT) LogProb(x float64) float64 { 67 g1, _ := math.Lgamma((s.Nu + 1) / 2) 68 g2, _ := math.Lgamma(s.Nu / 2) 69 z := (x - s.Mu) / s.Sigma 70 return g1 - g2 - 0.5*math.Log(s.Nu) - 0.5*logPi - math.Log(s.Sigma) - ((s.Nu+1)/2)*math.Log(1+z*z/s.Nu) 71 } 72 73 // Mean returns the mean of the probability distribution. 74 func (s StudentsT) Mean() float64 { 75 return s.Mu 76 } 77 78 // Mode returns the mode of the distribution. 79 func (s StudentsT) Mode() float64 { 80 return s.Mu 81 } 82 83 // NumParameters returns the number of parameters in the distribution. 84 func (StudentsT) NumParameters() int { 85 return 3 86 } 87 88 // Prob computes the value of the probability density function at x. 89 func (s StudentsT) Prob(x float64) float64 { 90 return math.Exp(s.LogProb(x)) 91 } 92 93 // Quantile returns the inverse of the cumulative distribution function. 94 func (s StudentsT) Quantile(p float64) float64 { 95 if p < 0 || p > 1 { 96 panic(badPercentile) 97 } 98 // F(x) = 1 - 0.5 * I_t(x)(nu/2, 1/2) 99 // t(x) = nu/(t^2 + nu) 100 if p == 0.5 { 101 return s.Mu 102 } 103 var y float64 104 if p > 0.5 { 105 // Know t > 0 106 t := mathext.InvRegIncBeta(s.Nu/2, 0.5, 2*(1-p)) 107 y = math.Sqrt(s.Nu * (1 - t) / t) 108 } else { 109 t := mathext.InvRegIncBeta(s.Nu/2, 0.5, 2*p) 110 y = -math.Sqrt(s.Nu * (1 - t) / t) 111 } 112 // Convert out of standard normal 113 return y*s.Sigma + s.Mu 114 } 115 116 // Rand returns a random sample drawn from the distribution. 117 func (s StudentsT) Rand() float64 { 118 // http://www.math.uah.edu/stat/special/Student.html 119 n := Normal{0, 1, s.Src}.Rand() 120 c := Gamma{s.Nu / 2, 0.5, s.Src}.Rand() 121 z := n / math.Sqrt(c/s.Nu) 122 return z*s.Sigma + s.Mu 123 } 124 125 // StdDev returns the standard deviation of the probability distribution. 126 // 127 // The standard deviation is undefined for ν <= 1, and this returns math.NaN(). 128 func (s StudentsT) StdDev() float64 { 129 return math.Sqrt(s.Variance()) 130 } 131 132 // Survival returns the survival function (complementary CDF) at x. 133 func (s StudentsT) Survival(x float64) float64 { 134 // transform to standard normal 135 y := (x - s.Mu) / s.Sigma 136 if y == 0 { 137 return 0.5 138 } 139 // For t > 0 140 // F(y) = 1 - 0.5 * I_t(y)(nu/2, 1/2) 141 // t(y) = nu/(y^2 + nu) 142 // and 1 - F(y) for t < 0 143 t := s.Nu / (y*y + s.Nu) 144 if y > 0 { 145 return 0.5 * mathext.RegIncBeta(s.Nu/2, 0.5, t) 146 } 147 return 1 - 0.5*mathext.RegIncBeta(s.Nu/2, 0.5, t) 148 } 149 150 // Variance returns the variance of the probability distribution. 151 // 152 // The variance is undefined for ν <= 1, and this returns math.NaN(). 153 func (s StudentsT) Variance() float64 { 154 if s.Nu <= 1 { 155 return math.NaN() 156 } 157 if s.Nu <= 2 { 158 return math.Inf(1) 159 } 160 return s.Sigma * s.Sigma * s.Nu / (s.Nu - 2) 161 }