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