Ejemplo n.º 1
0
        private Moments GetMoments([NotNull] Sample sample, Probability probability)
        {
            Assertion.NotNull(nameof(sample), sample);

            double n = sample.WeightedCount;
            double a = (n + 1) * probability, b = (n + 1) * (1 - probability);
            var    distribution  = new BetaDistribution(a, b);
            double targetPercent = 1.0 - TrimPercent;
            bool   symmetricMode = Math.Abs(probability - 0.5) < 1e-9;

            double c1 = 0;
            double c2 = 0;

            void Process(int j, double w)
            {
                c1 += w * sample.SortedValues[j];
                c2 += w * sample.SortedValues[j].Sqr();
            }

            double GetElementProbability(int j) => sample.IsWeighted
                ? sample.SortedWeights[j] / sample.TotalWeight
                : 1.0 / sample.Count;

            // Preparation
            double probabilityLeft = 0, probabilityRight = 0;
            int    indexLeft;

            for (indexLeft = 0; indexLeft < sample.Count; indexLeft++)
            {
                double elementProbability = GetElementProbability(indexLeft);
                probabilityLeft  = probabilityRight;
                probabilityRight = probabilityLeft + elementProbability;
                if (probabilityRight >= probability || indexLeft == sample.Count - 1)
                {
                    break;
                }
            }
            int    indexRight   = indexLeft;
            double betaCdfLeft  = distribution.Cdf(probabilityLeft);
            double betaCdfRight = distribution.Cdf(probabilityRight);

            Process(indexLeft, betaCdfRight - betaCdfLeft);
            double betaPdfLeft  = distribution.Pdf(probabilityLeft);
            double betaPdfRight = distribution.Pdf(probabilityRight);

            while ((betaCdfRight - betaCdfLeft < targetPercent ||
                    symmetricMode && (indexLeft != sample.Count - 1 - indexRight)) &&
                   (indexLeft > 0 || indexRight < sample.Count - 1))
            {
                if (indexLeft > 0 && (betaPdfLeft > betaPdfRight || indexRight == sample.Count - 1))
                {
                    // Expand to the left
                    int    indexNext       = indexLeft - 1;
                    double probabilityNext = probabilityLeft - GetElementProbability(indexNext);
                    double betaCdfNext     = distribution.Cdf(probabilityNext);
                    double betaPdfNext     = distribution.Pdf(probabilityNext);
                    Process(indexNext, betaCdfLeft - betaCdfNext);

                    indexLeft       = indexNext;
                    probabilityLeft = probabilityNext;
                    betaCdfLeft     = betaCdfNext;
                    betaPdfLeft     = betaPdfNext;
                }
                else
                {
                    // Expand to the right
                    int    indexNext       = indexRight + 1;
                    double probabilityNext = probabilityRight + GetElementProbability(indexNext);
                    double betaCdfNext     = distribution.Cdf(probabilityNext);
                    double betaPdfNext     = distribution.Pdf(probabilityNext);
                    Process(indexNext, betaCdfNext - betaCdfRight);

                    indexRight       = indexNext;
                    probabilityRight = probabilityNext;
                    betaCdfRight     = betaCdfNext;
                    betaPdfRight     = betaPdfNext;
                }
            }

            if (IsWinsorized)
            {
                // Processing winsorized elements
                Process(indexLeft, betaCdfLeft);
                Process(indexRight, 1 - betaCdfRight);
            }
            else
            {
                double scaleFactor = 1 / (betaCdfRight - betaCdfLeft);
                c1 *= scaleFactor;
                c2 *= scaleFactor;
            }

            return(new Moments(c1, c2, indexLeft, indexRight));
        }