寻求统计javascript函数以从z分数返回p值

时间:2013-04-24 14:31:42

标签: javascript jstat

我需要将z分数转换为百分位数。我找到了我可以使用的function in the jStat library的引用(jstat.ztest),但是jStat文档似乎领先于可用库,因为currently available version of the library中没有这样的函数。

我认为有more recent version of the library on GitHub,可能包含ztest函数,但我是linux新手,无法弄清楚如何从指令构建库。我花了大约一天时间学习git bash和cygwin试图构建库;我终于决定在这里问好了。

那么,有没有人能指出我能做我需要的javascript函数? 或者,是否有人可以指向包含ztest功能的jStat库的内置版本?

4 个答案:

答案 0 :(得分:16)

我在网上找到了一个论坛,它就像一个魅力。

function GetZPercent(z) 
  {
    //z == number of standard deviations from the mean

    //if z is greater than 6.5 standard deviations from the mean
    //the number of significant digits will be outside of a reasonable 
    //range
    if ( z < -6.5)
      return 0.0;
    if( z > 6.5) 
      return 1.0;

    var factK = 1;
    var sum = 0;
    var term = 1;
    var k = 0;
    var loopStop = Math.exp(-23);
    while(Math.abs(term) > loopStop) 
    {
      term = .3989422804 * Math.pow(-1,k) * Math.pow(z,k) / (2 * k + 1) / Math.pow(2,k) * Math.pow(z,k+1) / factK;
      sum += term;
      k++;
      factK *= k;

    }
    sum += 0.5;

    return sum;
  }

我不需要为一个函数包含一个大型库。

答案 1 :(得分:2)

只需编辑保罗答案中的代码进行双边t检验

function GetZPercent(z) 
{
//z == number of standard deviations from the mean

//if z is greater than 6.5 standard deviations from the mean
//the number of significant digits will be outside of a reasonable 
//range
if ( z < -6.5)
  return 0.0;
if( z > 6.5) 
  return 1.0;

if (z > 0) { z = -z;}

var factK = 1;
var sum = 0;
var term = 1;
var k = 0;
var loopStop = Math.exp(-23);
while(Math.abs(term) > loopStop) 
{
  term = .3989422804 * Math.pow(-1,k) * Math.pow(z,k) / (2 * k + 1) / Math.pow(2,k) * Math.pow(z,k+1) / factK;
  sum += term;
  k++;
  factK *= k;

}
sum += 0.5;

return (2*sum);
}

答案 2 :(得分:0)

这似乎是一个简单的问题,但是我很难跟踪执行此操作的库而不是复制一些随机代码段。最好的告诉我,这将使用简单统计信息库根据百分比计算z得分。

我阅读了他们关于“累积标准常态概率”的文档,并支持以下算法。感觉应该有一种更简单的方法,但谁知道呢。

https://simplestatistics.org/docs/#cumulativestdnormalprobability

const z_score = inverseErrorFunction((percentile_value - 0.5) / 0.5) * Math.sqrt(2);

答案 3 :(得分:0)

正如 Shane 已经正确说明的那样,该方程是普通 cdf 的泰勒展开式的实现。 sum 值在“真实”值的上方和下方以越来越高的精度迭代。如果该值接近 1 或 0,那么 sum 将 >1 或 <0 的可能性非常低,但存在的可能性很小,因为(相对)较早地被 loopstop 突破。 通过将 1/Math.sqrt(2*Math.Pi) 舍入为 0.3989422804 以及 javascript 浮点数的精度问题,进一步加强了偏差。此外,提供的解决方案不适用于 z-scores >7 或 <-7

我使用 decimal.js npm 库更新了代码以使其更准确并直接返回 p 值:

function GetpValueFromZ(_z, type = "twosided") 
{
    if(_z < -14)
    {
        _z = -14
    }
    else if(_z > 14)
    {
        _z = 14
    }
    Decimal.set({precision: 100});

    let z = new Decimal(_z);
    var sum = new Decimal(0);

    var term = new Decimal(1);
    var k = new Decimal(0);

    var loopstop = new Decimal("10E-50");
    var minusone = new Decimal(-1);
    var two = new Decimal(2);

    let pi = new Decimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647")

    while(term.abs().greaterThan(loopstop)) 
    {
        term = new Decimal(1)
    
        for (let i = 1; i <= k; i++) {
            term = term.times(z).times(z.dividedBy(two.times(i)))
        }
    
        term = term.times(minusone.toPower(k)).dividedBy(k.times(2).plus(1))        
        sum = sum.plus(term);
        k = k.plus(1);
    }
    
    sum = sum.times(z).dividedBy(two.times(pi).sqrt()).plus(0.5);

    if(sum.lessThan(0))
        sum = sum.abs();
    else if(sum.greaterThan(1))
        sum = two.minus(sum);

    switch (type) {
        case "left":
            return parseFloat(sum.toExponential(40));
        case "right":
            return parseFloat((new Decimal(1).minus(sum)).toExponential(40));
        case "twosided":
            return sum.lessThan(0.5)? parseFloat(sum.times(two).toExponential(40)) : parseFloat((new Decimal(1).minus(sum).times(two)).toExponential(40))
        
    }

}

通过增加 Decimal.js precision 值并减少 loopstop 值,您可以获得准确的 p 值,用于计算时间成本的非常小(或非常高)的 z 分数。< /p>