Scala Student’s t-distribution t分布由来定义用法示例源码
由来
在概率论和统计学中,学生t-分布(Student’s t-distribution)经常应用在对呈正态分布的总体的均值进行估计。它是对两个样本均值差异进行显著性测试的学生t测定的基础。t检定改进了Z检定(en:Z-test),不论样本数量大或小皆可应用。在样本数量大(超过30)时 [5],可以应用Z检定,但Z检定用在小的样本会产生很大的误差,因此样本很小的情况下得改用学生t检定。在数据有三组以上时,因为误差无法压低,此时可以用变异数分析代替学生t检定。
当母群体的标准差是未知的但却又需要估计时,可以使用学生t-分布。
学生t-分布可简称为t分布。其推导由威廉·戈塞于1908年首先发表,当时他还在都柏林的健力士酿酒厂工作。因为不能以他本人的名义发表,所以论文使用了学生(Student)这一笔名。之后t检验以及相关理论经由罗纳德·费雪的工作发扬光大,而正是他将此分布称为学生分布。
定义
由于在实际工作中,往往σ是未知的,常用s作为σ的估计值,为了与u变换区别,称为t变换,统计量t 值的分布称为t分布。 [1]
假设X服从标准正态分布N(0,1),Y服从 χ 2 ( n ) \chi ^{2}(n)\! χ2(n)分布,那么 Z = X ( Y / n ) Z=\frac{X}{\sqrt(Y/n)} Z=(Y/n)X
的分布称为自由度为n的t分布,记为 Z Z Z ~ t(n)。
分布密度函数
,
其中,Gam(x)为伽马函数。
分布密度函数
正态分布以及不同自由度的t分布的概率密度函数
代码示例
package org.example.scala
object TStudentTest extends App{
// 导入统计库
import org.apache.commons.math3.distribution.TDistribution
// 定义样本数据
val sample = Array(1.0, 2.0, 3.0, 4.0, 5.0)
// 创建学生t分布对象
val tDist = new TDistribution(sample.length - 1)
// 计算平均值和标准差
val mean = sample.sum / sample.length // 计算样本的平均值
val variance = sample.map(x => math.pow(x - mean, 2)).sum / (sample.length - 1) // 计算样本的方差
val stdDev = math.sqrt(variance) // 计算样本的标准差
// 计算置信区间
val confidenceLevel = 0.95 // 置信水平
val criticalValue = tDist.inverseCumulativeProbability(1 - (1 - confidenceLevel) / 2) // 根据自由度和置信水平计算临界值
val marginOfError = criticalValue * stdDev / math.sqrt(sample.length) // 计算误差范围
val lowerBound = mean - marginOfError // 置信区间下界
val upperBound = mean + marginOfError // 置信区间上界
// 计算t分布的CDF值
val tcdfValue = tDist.cumulativeProbability(1.5)
// 使用CDF值计算t分布的ICDF值
val invtcdfValue= tDist.inverseCumulativeProbability(tcdfValue)
// 打印结果
println(s"样本平均值: $mean")
println(s"样本标准差: $stdDev")
println(s"置信水平: $confidenceLevel")
println(s"临界值: $criticalValue")
println(s"误差范围: $marginOfError")
println(s"置信区间: [$lowerBound, $upperBound]")
println("t分布的CDF值: " + tcdfValue)
println("t分布的ICDF值: " + invtcdfValue)
// 样本平均值: 3.0
// 样本标准差: 1.5811388300841898
// 置信水平: 0.95
// 临界值: 2.7764451050184613
// 误差范围: 1.9632431613507502
// 置信区间: [1.0367568386492498, 4.96324316135075]
// t分布的CDF值: 0.8960000000000001
// t分布的ICDF值: 1.500000000000648
}
中文源码
/**
* 学生t分布类
*
* @param degreesOfFreedom 自由度
* @param randBasis 随机种子
*/
case class StudentsT(degreesOfFreedom: Double)(implicit randBasis: RandBasis = Rand) extends ContinuousDistr[Double] with Moments[Double, Double] with HasCdf {
require(degreesOfFreedom > 0, "degreesOfFreedom must be positive, but got " + degreesOfFreedom)
/**
* 将对象转为字符串
*
* @return 对象的字符串表示
*/
override def toString: String = ScalaRunTime._toString(this)
private val innerInstance = new TDistribution(randBasis.generator, degreesOfFreedom, TDistribution.DEFAULT_INVERSE_ABSOLUTE_ACCURACY)
/**
* 从学生t分布中随机生成一个数值
*
* @return 随机生成的数值
*/
def draw(): Double = {
// TODO: for small DoF this seems a little wrong..., StudentsT is even worse though.
// numpy version
val N = randBasis.gaussian.draw()
val G = new Gamma(degreesOfFreedom/2, 1.0).draw()
val X = sqrt(degreesOfFreedom/2)*N/sqrt(G)
X
}
/**
* 计算指定区间上的概率密度函数值
*
* @param x 区间下界
* @param y 区间上界
* @return 指定区间上的概率密度函数值
*/
override def probability(x: Double, y: Double): Double = {
val t = new org.apache.commons.math3.distribution.TDistribution(degreesOfFreedom)
t.probability(x, y)
}
/**
* 计算指定值的累积分布函数值
*
* @param x 指定值
* @return 指定值的累积分布函数值
*/
def cdf(x: Double):Double = {
val t = new org.apache.commons.math3.distribution.TDistribution(degreesOfFreedom)
t.cumulativeProbability(x)
}
/**
* 计算未归一化的概率密度函数值的对数
*
* @param x 指定值
* @return 未归一化的概率密度函数值的对数
*/
def unnormalizedLogPdf(x: Double): Double = -(degreesOfFreedom + 1)/2 * math.log(1 + (x * x)/degreesOfFreedom)
/**
* 对数归一化常数
*/
lazy val logNormalizer: Double = 0.5 * math.log(math.Pi * degreesOfFreedom) + lgamma(degreesOfFreedom / 2) - lgamma((degreesOfFreedom + 1)/2)
/**
* 计算均值
*
* @return 均值
*/
def mean: Double = innerInstance.getNumericalMean
/**
* 计算方差
*
* @return 方差
*/
def variance: Double = innerInstance.getNumericalVariance
/**
* 计算熵
*
* @return 熵
*/
def entropy: Double = (
(degreesOfFreedom + 1)/2 * (digamma((degreesOfFreedom + 1)/2) - digamma(degreesOfFreedom))
- .5 * log(degreesOfFreedom)
+ lbeta(degreesOfFreedom/2, 0.5)
)
/**
* 计算众数
*
* @return 众数
*/
def mode: Double = mean
}
/**
* 学生t分布对象
*/
object StudentsT extends ContinuousDistributionUFuncProvider[Double,StudentsT]
om/2, 0.5)
)
/**
* 计算众数
*
* @return 众数
*/
def mode: Double = mean
}
/**
- 学生t分布对象
*/
object StudentsT extends ContinuousDistributionUFuncProvider[Double,StudentsT]
# [参考](https://baike.baidu.com/item/t%E5%88%86%E5%B8%83/299142)