Пример #1
0
        /// <summary>
        /// Returns the largest value x such that GetProbLessThan(x) &lt;= probability.
        /// </summary>
        /// <param name="probability">A real number in [0,1].</param>
        /// <returns></returns>
        public double GetQuantile(double probability)
        {
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability < 0");
            }
            if (probability > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability > 1.0");
            }
            int n = quantiles.Length;

            if (probability < 1.0 / (n + 1.0))
            {
                return(Math.Min(quantiles[0], lowerGaussian.GetQuantile(probability)));
            }
            if (probability > n / (n + 1.0))
            {
                return(Math.Max(quantiles[n - 1], upperGaussian.GetQuantile(probability)));
            }
            if (n == 1)
            {
                return(quantiles[0]);        // probability must be 0.5
            }
            double pos   = MMath.LargestDoubleProduct(n + 1, probability) - 1;
            int    lower = (int)Math.Floor(pos);

            if (lower == n - 1)
            {
                return(quantiles[lower]);
            }
            return(OuterQuantiles.GetQuantile(probability, lower + 1, quantiles[lower], quantiles[lower + 1], n + 2));
        }
Пример #2
0
 public InnerQuantiles(int quantileCount, CanGetQuantile canGetQuantile)
 {
     if (quantileCount == 0)
     {
         throw new ArgumentException("quantileCount == 0", nameof(quantiles));
     }
     this.quantiles = new double[quantileCount];
     for (int i = 0; i < quantileCount; i++)
     {
         this.quantiles[i] = canGetQuantile.GetQuantile((i + 1.0) / (quantileCount + 1.0));
     }
     OuterQuantiles.AssertFinite(quantiles, nameof(canGetQuantile));
     OuterQuantiles.AssertNondecreasing(quantiles, nameof(canGetQuantile));
     lowerGaussian = GetLowerGaussian(quantiles);
     upperGaussian = GetUpperGaussian(quantiles);
 }
Пример #3
0
 public InnerQuantiles(double[] quantiles)
 {
     if (quantiles == null)
     {
         throw new ArgumentNullException(nameof(quantiles));
     }
     if (quantiles.Length == 0)
     {
         throw new ArgumentException("quantiles array is empty", nameof(quantiles));
     }
     OuterQuantiles.AssertFinite(quantiles, nameof(quantiles));
     OuterQuantiles.AssertNondecreasing(quantiles, nameof(quantiles));
     this.quantiles = quantiles;
     lowerGaussian  = GetLowerGaussian(quantiles);
     upperGaussian  = GetUpperGaussian(quantiles);
 }
Пример #4
0
        /// <summary>
        /// Returns the largest value x such that GetProbLessThan(x) &lt;= probability.
        /// </summary>
        /// <param name="probability">A real number in [0,1].</param>
        /// <returns></returns>
        public double GetQuantile(double probability)
        {
            if (double.IsNaN(probability))
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability is NaN");
            }
            if (probability < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability < 0");
            }
            if (probability > 1.0)
            {
                throw new ArgumentOutOfRangeException(nameof(probability), "probability > 1.0");
            }
            // compute the min and max of the retained items
            double lowerBound = double.PositiveInfinity, upperBound = double.NegativeInfinity;
            bool   countGreaterThanZero = false;

            for (int bufferIndex = 0; bufferIndex < buffers.Length; bufferIndex++)
            {
                double[] buffer = buffers[bufferIndex];
                int      count  = countInBuffer[bufferIndex];
                if (count > 0)
                {
                    countGreaterThanZero = true;
                }
                for (int i = 0; i < count; i++)
                {
                    double item = buffer[i];
                    if (item < lowerBound)
                    {
                        lowerBound = item;
                    }
                    if (item > upperBound)
                    {
                        upperBound = item;
                    }
                }
            }
            if (probability == 1.0)
            {
                return(MMath.NextDouble(upperBound));
            }
            if (probability == 0.0)
            {
                return(lowerBound);
            }
            if (!countGreaterThanZero)
            {
                throw new Exception("QuantileEstimator has no data");
            }
            if (lowerBound == upperBound)
            {
                return(upperBound);
            }
            // use bisection
            while (true)
            {
                double x = MMath.Average(lowerBound, upperBound);
                double lowerItem;
                double upperItem;
                long   lowerRank;
                long   lowerWeight, minLowerWeight, upperWeight, minUpperWeight;
                long   itemCount;
                GetAdjacentItems(x, out lowerItem, out upperItem, out lowerRank, out lowerWeight, out upperWeight, out minLowerWeight, out minUpperWeight, out itemCount);
                if (InterpolationType == 0)
                {
                    double probabilityLessThanLowerItem = (double)(lowerRank - lowerWeight) / itemCount;
                    if (probability < probabilityLessThanLowerItem)
                    {
                        upperBound = MMath.PreviousDouble(lowerItem);
                    }
                    else
                    {
                        double probabilityLessThanUpperItem = (double)lowerRank / itemCount;
                        if (probability < probabilityLessThanUpperItem)
                        {
                            return(lowerItem);
                        }
                        double probabilityLessThanOrEqualUpperItem = (double)(lowerRank + upperWeight) / itemCount;
                        if (probability < probabilityLessThanOrEqualUpperItem)
                        {
                            return(upperItem);
                        }
                        lowerBound = MMath.NextDouble(upperItem);
                    }
                    if (lowerBound > upperBound)
                    {
                        throw new Exception("lowerBound > upperBound");
                    }
                }
                else if (InterpolationType == 1)
                {
                    // Find frac such that (lowerRank - 0.5 + frac) / itemCount == probability
                    double scaledProbability = MMath.LargestDoubleProduct(itemCount, probability);
                    if (scaledProbability < 0.5)
                    {
                        return(lowerBound);
                    }
                    if (scaledProbability >= itemCount - 0.5)
                    {
                        return(upperBound);
                    }
                    // probability of lowerItem ranges from (lowerRank-lowerWeight+0.5) / itemCount
                    // to (lowerRank - 0.5) / itemCount
                    //if (scaledProbability == lowerRank - lowerWeight + 0.5) return lowerItem;
                    if ((scaledProbability > lowerRank - lowerWeight + 0.5) && (scaledProbability < lowerRank - 0.5))
                    {
                        return(lowerItem);
                    }
                    // probability of upperItem ranges from (lowerRank + 0.5) / itemCount
                    // to (lowerRank + upperWeight - 0.5) / itemCount
                    if (scaledProbability == lowerRank + 0.5)
                    {
                        return(upperItem);
                    }
                    if ((scaledProbability > lowerRank + 0.5) && (scaledProbability < lowerRank + upperWeight - 0.5))
                    {
                        return(upperItem);
                    }
                    double frac = scaledProbability - (lowerRank - 0.5);
                    if (frac < 0)
                    {
                        upperBound = MMath.PreviousDouble(x);
                    }
                    else if (frac > 1)
                    {
                        lowerBound = MMath.NextDouble(x);
                    }
                    else
                    {
                        return(OuterQuantiles.GetQuantile(probability, lowerRank - 0.5, lowerItem, upperItem, itemCount + 1));
                    }
                }
                else
                {
                    double scaledProbability = MMath.LargestDoubleProduct(itemCount - 1, probability);
                    // probability of lowerItem ranges from (lowerRank-lowerWeight) / (itemCount - 1)
                    // to (lowerRank - 1) / (itemCount - 1).
                    if (scaledProbability == lowerRank - lowerWeight)
                    {
                        return(lowerItem);
                    }
                    if ((scaledProbability > lowerRank - lowerWeight) && (scaledProbability < lowerRank - 1))
                    {
                        return(lowerItem);
                    }
                    // probability of upperItem ranges from lowerRank / (itemCount - 1)
                    // to (lowerRank + upperWeight-1) / (itemCount - 1)
                    if (scaledProbability == lowerRank)
                    {
                        return(upperItem);
                    }
                    if ((scaledProbability > lowerRank) && (scaledProbability < lowerRank + upperWeight - 1))
                    {
                        return(upperItem);
                    }
                    // solve for frac in (lowerRank-1 + frac) / (itemCount - 1) == probability
                    double frac = scaledProbability - (lowerRank - 1);
                    if (frac < 0)
                    {
                        upperBound = MMath.PreviousDouble(x);
                    }
                    else if (frac > 1)
                    {
                        lowerBound = MMath.NextDouble(x);
                    }
                    else
                    {
                        return(OuterQuantiles.GetQuantile(probability, lowerRank - 1, lowerItem, upperItem, itemCount));
                    }
                }
            }
        }