示例#1
0
        /// <summary>
        /// Finds the moving median sequence from the sequence of values
        /// and the specified non-negative window width. The tail values
        /// (such that there is not enough data in the window around them
        /// get handled using <see cref="TailValuesHandling"/> flag passed).
        /// </summary>
        /// <typeparam name="T">The type of elements in the sequence.</typeparam>
        /// <typeparam name="C">The numeric calculator for the <typeparamref name="T"/> type.</typeparam>
        /// <param name="values">The sequence of values.</param>
        /// <param name="windowWidth">
        /// A non-negative window width applied to both sides of the current value.
        /// It means that, e.g. when the window width is 1, the window will consist
        /// of three values: the current value, one value to the left and one value to the right.
        /// </param>
        /// <param name="windowType">
        /// The type of the window for calculation of the median.
        /// See <see cref="WindowType"/>
        /// </param>
        /// <param name="tailValuesHandling">
        /// A flag specifying how the tail values should be handled
        /// (such that there is not enough data in the window around them).
        /// See <see cref="TailValuesHandling"/>.
        /// </param>
        /// <returns>A sequence of moving medians calculated from the source sequence.</returns>
        public static List <T> MovingMedian <T, C>(
            this IList <T> values,
            int windowWidth,
            WindowType windowType = WindowType.Symmetric,
            TailValuesHandling tailValuesHandling = TailValuesHandling.UseSymmetricAvailableWindow)
            where C : ICalc <T>, new()
        {
            Contract.Requires <ArgumentNullException>(values != null, "values");
            Contract.Requires <ArgumentOutOfRangeException>(windowWidth >= 0, "The window width should be non-negative");
            Contract.Requires <ArgumentException>(
                tailValuesHandling != TailValuesHandling.UseSymmetricAvailableWindow ||
                windowType == WindowType.Symmetric,
                "Symmetric tail values handling is only available for symmetric windows.");

            return(MovingStatistic <T, C>(
                       values,
                       windowWidth,
                       windowType,
                       tailValuesHandling,
                       StatisticExtensionMethods.SampleAverage <T, C>));
        }
示例#2
0
        /// <summary>
        /// Finds the moving statistic sequence from the sequence of values
        /// using the specified non-negative window width and the statistic functor
        /// <paramref name="statistic"/> of type <c>Func&lt;IEnumerable&lt;T&gt;, T&gt;"</c>.
        ///
        /// The tail values (such that there is not enough data in the window around them
        /// get handled using <see cref="TailValuesHandling"/> flag passed).
        /// </summary>
        /// <typeparam name="T">The type of elements in the sequence.</typeparam>
        /// <typeparam name="C">The numeric calculator for the <typeparamref name="T"/> type.</typeparam>
        /// <param name="values">The sequence of values.</param>
        /// <param name="windowWidth">
        /// A non-negative window width applied to both sides of the current value.
        /// It means that, e.g. when the window width is 1, the window will consist
        /// of three values: the current value, one value to the left and one value to the right.
        /// </param>
        /// <param name="windowType">
        /// The type of the window for calculation of the average.
        /// See <see cref="WindowType"/>
        /// </param>
        /// <param name="tailValuesHandling">
        /// A flag specifying how the tail values should be handled
        /// (such that there is not enough data in the window around them).
        /// See <see cref="TailValuesHandling"/>.
        /// </param>
        /// <param name="statistic">
        /// A functor object taking an <c>IEnumerable&lt;T&gt;</c> sequence of observations
        /// and returning a statistic such as sample average, sample median, sample variance / standard
        /// deviation etc.
        /// </param>
        /// <returns>
        /// A sequence of statictics calculated in the window
        /// around each value from the source sequence.
        /// i.e. the i-th index in the result sequence means
        /// that the <paramref name="statistic"/> was calculated in the
        /// respective window around the i-th element of the source sequence.
        /// </returns>
        public static List <T> MovingStatistic <T, C>(
            this IList <T> values,
            int windowWidth,
            WindowType windowType,
            TailValuesHandling tailValuesHandling,
            Func <IEnumerable <T>, T> statistic)
            where C : ICalc <T>, new()
        {
            Contract.Requires <ArgumentNullException>(values != null, "values");
            Contract.Requires <ArgumentOutOfRangeException>(windowWidth >= 0, "The window width should be non-negative");
            Contract.Requires <ArgumentException>(
                tailValuesHandling != TailValuesHandling.UseSymmetricAvailableWindow ||
                windowType == WindowType.Symmetric,
                "Symmetric tail values handling is only available for symmetric windows.");

            List <T> result = new List <T>(values.Count);

            for (int index = 0; index < values.Count; ++index)
            {
                ListSegment <T> windowSequence = __getWindowSequence <T>(
                    values,
                    windowWidth,
                    windowType,
                    tailValuesHandling,
                    index);

                if (windowSequence.IsEmpty())
                {
                    continue;
                }
                else
                {
                    T statisticValue = statistic(windowSequence);
                    result.Add(statisticValue);
                }
            }

            return(result);
        }
示例#3
0
        /// <summary>
        /// Having passed the list of values,
        /// a non-negative window width, and
        /// a <see cref="TailValuesHandling"/> flag,
        /// returns the appropriate segment of the source
        /// list containing the values falling in the window.
        /// </summary>
        /// <typeparam name="T">The type of elements in the sequence.</typeparam>
        /// <param name="values">The source sequence.</param>
        /// <param name="windowWidth">A non-negative window width.</param>
        /// <param name="currentIndex">
        /// The current index in the source sequence
        /// pointing to the current element (for which the window sequence is calculated)</param>
        /// <param name="tailValuesHandling">A tail values handling flag, see <see cref="TailValuesHandling"/></param>
        /// <param name="windowType">The window type, see <see cref="WindowType"/>.</param>
        /// <returns>
        /// A window sequence for the current element (referenced by <paramref name="currentIndex"/>).
        /// The sequence can then be used for calculating the average or the median value.
        ///
        /// If the value is a tail value that should be excluded (see <see cref="TailValuesHandling.DoNotInclude"/>),
        /// this method returns an empty list segment.
        /// </returns>
        private static ListSegment <T> __getWindowSequence <T>(
            IList <T> values,
            int windowWidth,
            WindowType windowType,
            TailValuesHandling tailValuesHandling,
            int currentIndex)
        {
            Contract.Requires <ArgumentNullException>(values != null, "values");
            Contract.Requires <ArgumentOutOfRangeException>(windowWidth >= 0, "The window width should be non-negative.");
            Contract.Requires <IndexOutOfRangeException>(currentIndex >= 0 && currentIndex < values.Count, "The index is out of range");

            // Check the available number of elements to the left
            // and to the right of the current value.
            // -
            int amountToTheLeft  = currentIndex;
            int amountToTheRight = values.Count - currentIndex - 1;

            bool isLeftTailValue  = amountToTheLeft < windowWidth && windowType != WindowType.Forward;
            bool isRightTailValue = amountToTheRight < windowWidth && windowType != WindowType.Backward;

            // These are the boundary indices in the resulting
            // list segment. To be modified further.
            // -
            int leftIndex  = currentIndex - (windowType == WindowType.Forward ? 0 : windowWidth);
            int rightIndex = currentIndex + (windowType == WindowType.Backward ? 0 : windowWidth);

            switch (tailValuesHandling)
            {
            case TailValuesHandling.DoNotInclude:

                if (isLeftTailValue || isRightTailValue)
                {
                    return(new ListSegment <T>(values, currentIndex, 0));
                }
                break;

            case TailValuesHandling.DoNotTouch:

                if (isLeftTailValue || isRightTailValue)
                {
                    leftIndex  = currentIndex;
                    rightIndex = currentIndex;
                }
                break;

            case TailValuesHandling.UseAllAvailableWindow:

                if (isLeftTailValue)
                {
                    leftIndex = currentIndex - amountToTheLeft;
                }
                if (isRightTailValue)
                {
                    rightIndex = currentIndex + amountToTheRight;
                }
                break;

            case TailValuesHandling.UseSymmetricAvailableWindow:

                if (isLeftTailValue || isRightTailValue)
                {
                    int minimumAmountAvaliable = Math.Min(amountToTheLeft, amountToTheRight);

                    leftIndex  = currentIndex - minimumAmountAvaliable;
                    rightIndex = currentIndex + minimumAmountAvaliable;
                }
                break;

            default:
                throw new EnumFattenedException("Ouch!");
            }

            return(new ListSegment <T>(values, leftIndex, rightIndex - leftIndex + 1));
        }