我想在Matlab中为小值(例如1e-18)评估逆学生 t - 分布函数。自由度是2。
不幸的是,Matlab返回NaN
:
tinv(1e-18,2)
NaN
但是,如果我使用R&#39的内置功能:
qt(1e-18,2)
-707106781
结果是明智的。为什么Matlab不能评估这个小值的函数? Matlab和R的结果非常类似于1e-15,但是对于较小的值,差异是相当大的:
tinv(1e-16,2)/qt(1e-16,2) = 1.05
有没有人知道Matlab和R的实现算法有什么不同,如果R给出了正确的结果,我怎样才能有效地计算Matlab中的逆 t -distribution,以获得更小的值?
答案 0 :(得分:5)
似乎R qt
可能使用completely different algorithm而不是Matlab的tinv
。我认为您和其他人应该通过提交service request向The MathWorks报告此缺陷。顺便说一下,在R2014b和R2015a中,对于第一个参数-Inf
的小值(大约NaN
和更小),返回eps/8
而不是p
。这更明智,但我认为他们应该做得更好。
在此期间,有几种解决方法。
特殊情况
首先,在Student's t-distribution的情况下,对于反向CDF有several simple analytic solutions或对于ν的某些整数参数有quantile function。对于ν = 2的例子:
% for v = 2
p = 1e-18;
x = (2*p-1)./sqrt(2*p.*(1-p))
返回-7.071067811865475e+08
。至少,Matlab的tinv
应该包含这些特殊情况(它们只对ν = 1这样做)。它也可能会提高这些特定解决方案的准确性和速度。
数字反转
tinv
函数基于betaincinv
函数。似乎这个函数可能导致第一个参数p
的小值的精度损失。但是,如OP所建议的,可以使用CDF函数tcdf
和根寻找方法来数值地评估逆CDF。 tcdf
函数基于betainc
,它似乎不敏感。使用fzero
:
p = 1e-18;
v = 2
x = fzero(@(x)tcdf(x,v)-p, 0)
返回-7.071067811865468e+08
。请注意,对于p
接近1
的值,此方法不是非常健壮。
符号解决方案
对于更一般的情况,您可以利用symbolic math和variable precision arithmetic。您可以将Gausian hypergeometric functions, 2 F 1 中的标识用作CDF的given here。因此,使用solve
和hypergeom
:
% Supposedly valid for or x^2 < v, but appears to work for your example
p = sym('1e-18');
v = sym(2);
syms x
F = 0.5+x*gamma((v+1)/2)*hypergeom([0.5 (v+1)/2],1.5,-x^2/v)/(sqrt(sym('pi')*v)*gamma(v/2));
sol_x = solve(p==F,x);
vpa(sol_x)
tinv
函数基于betaincinv
函数。符号数学工具箱或MuPAD中没有等效函数甚至不完整的Beta函数,但{的 2 F 1 关系类似可以使用{3}}:
p = sym('1e-18');
v = sym(2);
syms x
a = v/2;
F = 1-x^a*hypergeom([a 0.5],a+1,x)/(a*beta(a,0.5));
sol_x = solve(2*abs(p-0.5)==F,x);
sol_x = sign(p-0.5).*sqrt(v.*(1-sol_x)./sol_x);
vpa(sol_x)
两种符号方案都使用默认值-707106781.186547523340184
返回同意digits
的结果。
我还没有完全验证上面的两种符号方法,所以在所有情况下我都不能保证它们的正确性。代码也需要进行矢量化,并且比完全数值解决方案慢。