11

我需要将 z 分数转换为百分位数。我在 jStat 库中找到了一个我可以使用的函数的引用(jstat.ztest),但是 jStat 文档似乎领先于可用的库,因为在当前可用的库版本中没有这样的函数。

我认为GitHub 上有该库的更新版本,其中可能包含 ztest 函数,但我是 linux 新手,无法弄清楚如何根据说明构建库。我花了一天的大部分时间学习 git bash 和 cygwin 尝试构建库;我终于决定我最好在这里问。

那么,任何人都可以将我指向一个可以满足我需要的javascript函数吗?或者,任何人都可以将我指向包含 ztest 函数的 jStat 库的构建版本吗?

4

4 回答 4

19

我在网上的一个论坛上发现了这个,它就像一个魅力。

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;
  }

而且我不需要只为一个功能包含一个大型库。

于 2013-04-24T16:31:25.497 回答
2

只需编辑 Paul 答案中的代码即可进行双边 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);
}
于 2015-05-25T10:08:40.987 回答
0

正如 Shane 已经正确指出的那样,该方程是正常 cdf 的泰勒展开的实现。该sum值在“真实”值的上下迭代,精度越来越高。如果该值接近 1 或 0,则存在一个非常低但存在的概率,即sum>1 或 <0,因为(相对)较早的突破loopstop1/Math.sqrt(2*Math.Pi)通过舍入0.3989422804和javascript浮点数的精度问题进一步加强了偏差。此外,提供的解决方案不适用于 z 分数 >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.jsprecision值并减少该loopstop值,您可以获得非常小(或非常高)z 分数的准确 p 值,以计算时间成本。

于 2021-06-17T08:45:27.040 回答
0

This seems like such a simple ask but I had a hard time tracking down a library that does this instead of copying some random code snippet. Best I can tell this will calculate z-score from a percentage using the simple-statistics library.

I took their documentation about cumulativestdnormalprobability and backed into the following algorithm. Feels like there should be an easier way but who knows.

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

const z_score = inverseErrorFunction((percentile_value - 0.5) / 0.5) * Math.sqrt(2);
于 2020-08-10T19:04:29.703 回答