C# 如何将标准偏差为1的反向CDF编码转换为不同的STDEV?
我使用逆累积分布函数(CDF)进行拒绝采样,作为数值积分算法的一部分 我发现了两种可能的实现:C# 如何将标准偏差为1的反向CDF编码转换为不同的STDEV?,c#,probability,standard-deviation,C#,Probability,Standard Deviation,我使用逆累积分布函数(CDF)进行拒绝采样,作为数值积分算法的一部分 我发现了两种可能的实现: 在C和Java(以及其他语言,但不是C#,所以我需要翻译): 在C#中,存在StatisticFormula.InversionNormalDistribution(在System.Windows.Forms.DataVisualization.Charting中)。考虑到微软多年前在Excel中实施NORMINV的记录,我对此持怀疑态度 这两个函数都假设平均值为零(这就是我将要使用的),标准偏差为
将高斯变换为不同的Std-Dev是很容易的我可以对反向CDF执行类似操作吗?当所有其他操作都失败时,请尝试MS Excel。我使用NORMINV计算了反向CDF(它允许您提供标准偏差),并将其与使用NORMSINV返回的值进行比较(它假设std dev为1)。令人高兴的结果是,您可以将使用标准偏差1得到的结果乘以所需的标准偏差 NORMSINV(x)*SD=NORMINV(x,0,SD) 顺便说一句:我试图使用微软图书馆,但没有成功。只能在图表的上下文中调用函数,这是不可接受的开销。我最终将Jeremy Lea的C实现移植到了C。引用了我在问题中给出的链接
我要么在移植中犯了错误,要么C版本有错误,因为我对负输入获得了很好的精度,但当x>6时,精度迅速下降,并以x=7消失。由于Paul Chernoch的答案中与实现的链接中断,我不得不寻找我自己的答案。我发现R版本的反向CDF的实现具有参数化的平均值和标准偏差: 为了防止另一个断开链接的风险,我在下面列出了我的方法副本
/// <summary>
/// Quantile function (Inverse CDF) for the normal distribution.
/// </summary>
/// <param name="p">Probability.</param>
/// <param name="mu">Mean of normal distribution.</param>
/// <param name="sigma">Standard deviation of normal distribution.</param>
/// <param name="isLowerTail">If true, probability is P[X <= x], otherwise P[X > x].</param>
/// <param name="isLogValues">If true, probabilities are given as log(p).</param>
/// <returns>P[X <= x] where x ~ N(mu,sigma^2)</returns>
/// <remarks>See https://svn.r-project.org/R/trunk/src/nmath/qnorm.c </remarks>
public static double QNorm(double p, double mu, double sigma, bool isLowerTail, bool isLogValues)
{
if (double.IsNaN(p) || double.IsNaN(mu) || double.IsNaN(sigma)) return (p + mu + sigma);
double ans;
bool isBoundaryCase = R_Q_P01_boundaries(p, double.NegativeInfinity, double.PositiveInfinity, isLowerTail, isLogValues, out ans);
if (isBoundaryCase) return (ans);
if (sigma < 0) return (double.NaN);
if (sigma == 0) return (mu);
double p_ = R_DT_qIv(p, isLowerTail, isLogValues);
double q = p_ - 0.5;
double r, val;
if (Math.Abs(q) <= 0.425) // 0.075 <= p <= 0.925
{
r = .180625 - q * q;
val = q * (((((((r * 2509.0809287301226727 +
33430.575583588128105) * r + 67265.770927008700853) * r +
45921.953931549871457) * r + 13731.693765509461125) * r +
1971.5909503065514427) * r + 133.14166789178437745) * r +
3.387132872796366608)
/ (((((((r * 5226.495278852854561 +
28729.085735721942674) * r + 39307.89580009271061) * r +
21213.794301586595867) * r + 5394.1960214247511077) * r +
687.1870074920579083) * r + 42.313330701600911252) * r + 1.0);
}
else
{
r = q > 0 ? R_DT_CIv(p, isLowerTail, isLogValues) : p_;
r = Math.Sqrt(-((isLogValues && ((isLowerTail && q <= 0) || (!isLowerTail && q > 0))) ? p : Math.Log(r)));
if (r <= 5) // <==> min(p,1-p) >= exp(-25) ~= 1.3888e-11
{
r -= 1.6;
val = (((((((r * 7.7454501427834140764e-4 +
.0227238449892691845833) * r + .24178072517745061177) *
r + 1.27045825245236838258) * r +
3.64784832476320460504) * r + 5.7694972214606914055) *
r + 4.6303378461565452959) * r +
1.42343711074968357734)
/ (((((((r *
1.05075007164441684324e-9 + 5.475938084995344946e-4) *
r + .0151986665636164571966) * r +
.14810397642748007459) * r + .68976733498510000455) *
r + 1.6763848301838038494) * r +
2.05319162663775882187) * r + 1.0);
}
else // very close to 0 or 1
{
r -= 5.0;
val = (((((((r * 2.01033439929228813265e-7 +
2.71155556874348757815e-5) * r +
.0012426609473880784386) * r + .026532189526576123093) *
r + .29656057182850489123) * r +
1.7848265399172913358) * r + 5.4637849111641143699) *
r + 6.6579046435011037772)
/ (((((((r *
2.04426310338993978564e-15 + 1.4215117583164458887e-7) *
r + 1.8463183175100546818e-5) * r +
7.868691311456132591e-4) * r + .0148753612908506148525)
* r + .13692988092273580531) * r +
.59983220655588793769) * r + 1.0);
}
if (q < 0.0) val = -val;
}
return (mu + sigma * val);
}
private static bool R_Q_P01_boundaries(double p, double left, double right, bool isLowerTail, bool isLogValues, out double ans)
{
if (isLogValues)
{
if (p > 0.0)
{
ans = double.NaN;
return (true);
}
if (p == 0.0)
{
ans = isLowerTail ? right : left;
return (true);
}
if (p == double.NegativeInfinity)
{
ans = isLowerTail ? left : right;
return (true);
}
}
else
{
if (p < 0.0 || p > 1.0)
{
ans = double.NaN;
return (true);
}
if (p == 0.0)
{
ans = isLowerTail ? left : right;
return (true);
}
if (p == 1.0)
{
ans = isLowerTail ? right : left;
return (true);
}
}
ans = double.NaN;
return (false);
}
private static double R_DT_qIv(double p, bool isLowerTail, bool isLogValues)
{
return (isLogValues ? (isLowerTail ? Math.Exp(p) : -ExpM1(p)) : R_D_Lval(p, isLowerTail));
}
private static double R_DT_CIv(double p, bool isLowerTail, bool isLogValues)
{
return (isLogValues ? (isLowerTail ? -ExpM1(p) : Math.Exp(p)) : R_D_Cval(p, isLowerTail));
}
private static double R_D_Lval(double p, bool isLowerTail)
{
return isLowerTail ? p : 0.5 - p + 0.5;
}
private static double R_D_Cval(double p, bool isLowerTail)
{
return isLowerTail ? 0.5 - p + 0.5 : p;
}
private static double ExpM1(double x)
{
if (Math.Abs(x) < 1e-5)
return x + 0.5 * x * x;
else
return Math.Exp(x) - 1.0;
}
//
///正态分布的分位数函数(逆CDF)。
///
///概率。
///正态分布均值。
///正态分布的标准差。
///如果为真,则概率为P[X]。
///如果为true,则概率以log(p)表示。
///P[X链接已断开。你有其他参考资料吗?抱歉-我为前雇主编写了C#版本,不再有源代码。不用担心。我在网上找到了一个实现。我添加了它作为答案。