示例#1
0
   /// Normal-distribution percent point function, or inverse of the Normal CDF.
   /// This function(prob,mu,sig) == X where prob = NormalCDF(X,mu,sig).
   /// Ref http://www.itl.nist.gov/div898/handbook/ 1.3.6.6.1
   /// @param prob probability or significance level of the test, >=0 and < 1
   /// @param mu  mean of the sample (location parameter of the distribution)
   /// @param sig std dev of the sample (scale parameter of the distribution)
   /// @return        X the statistic at this probability
   double invNormalCDF(double prob, const double& mu, const double& sig)
      throw(Exception)
   {
      try {
         if(prob < 0 || prob >= 1)
            GPSTK_THROW(Exception("Invalid probability argument"));
         if(sig <= 0.0) GPSTK_THROW(Exception("Non-positive sigma"));

         static const double eps(1000000*std::numeric_limits<double>().epsilon());

         if(prob < eps)
            return 0.0;
         if(1.0-prob < eps)
            GPSTK_THROW(Exception("Invalid probability -- too close to 1.0"));

         // find X such that prob == NormalCDF(X,mu,sig); use bracket method
         // we know 0.5 = NormalCDF(muwhen prob = 0.5, X = mu
         // also invNormalCDF(1-prob,mu,sig) = 2*mu - invNormalCDF(prob,mu,sig)
         // so make alpha >= 0.5
         bool swap(false);
         double alpha(prob);
         if(prob < 0.5) { swap=true; alpha=1.0-prob; }

         // we know a0 = NormalCDF(X0,mu,sig) where a0=0.5,X0=mu and alpha >= 0.5
         double X,X0(mu),X1,a;
         // first find X1 such that a1 = NormalCDF(X1,mu,sig) and a1 > alpha
         X1 = 2.0;
         while((a = NormalCDF(X1,mu,sig)) <= alpha) { X1 *= 2.0; }

         // bracket
         int niter(0);      // iteration count
         while(1) {
            X = (X0+X1)/2.0;
            a = NormalCDF(X,mu,sig);
            //LOG(INFO) << "LOOP invNormalCDF X = " << niter << " " << std::fixed
            //<< std::setprecision(15) << X0 << " < " << X << " < " << X1
            //<< " and a = " << a << " alpha = " << alpha << " a-alpha = "
            //<< std::scientific << std::setprecision(2) << a-alpha << " eps " << eps
            //<< " fabs(a-alpha)-eps " << ::fabs(alpha-a)-eps;
            if(::fabs(alpha-a) < eps) break;
            if(a > alpha) { X1 = X; } else { X0 = X; }
            if(++niter > 100) GPSTK_THROW(Exception("Failed to converge"));
         }

         return (swap ? 2.0*mu-X : X);
      }
      catch(Exception& e) { GPSTK_RETHROW(e); }
   }
示例#2
0
TWxTestResult WxTest(const TVector<double>& baseline,
                     const TVector<double>& test) {
    TVector<double> diffs;

    for (ui32 i = 0; i < baseline.size(); i++) {
        const double i1 = baseline[i];
        const double i2 = test[i];
        const double diff = i1 - i2;
        if (diff != 0) {
            diffs.push_back(diff);
        }
    }

    if (diffs.size() < 2) {
        TWxTestResult result;
        result.PValue = 0.5;
        result.WMinus = result.WPlus = 0;
        return result;
    }

    Sort(diffs.begin(), diffs.end(), [&](double x, double y) {
        return Abs(x) < Abs(y);
    });

    double w_plus = 0;
    double w_minus = 0;
    double n = diffs.size();


    for (int i = 0; i < n; ++i) {
        double sum = 0;
        double weight = 0;
        int j = i;
        double signPlus = 0;
        double signMinus = 0;

        for (j = i; j < n && diffs[j] == diffs[i]; ++j) {
            sum += (j + 1);
            ++weight;
            signPlus += diffs[i] >= 0;
            signMinus += diffs[i] < 0;
        }

        const double meanRank = sum / weight;
        w_plus += signPlus * meanRank;
        w_minus += signMinus * meanRank;

        i = j - 1;
    }

    TWxTestResult result;
    result.WPlus = w_plus;
    result.WMinus = w_minus;

    const double w = result.WPlus - result.WMinus;
    if (n > 16) {
        double z = w / sqrt(n * (n + 1) * (2 * n + 1) * 1.0 / 6);
        result.PValue = 2 * (1.0 - NormalCDF(Abs(z)));
    } else {
        result.PValue = 2 * CalcLevelOfSignificanceWXMPSR(Abs(w), (int) n);
    }
    result.PValue = 1.0 - result.PValue;
    return result;
}