Repository navigation
Conversation
The Commons Statistics Quantile used by Statistics.Percentile and StatUtils was built with withCopy(false), so it partially sorts the array it is given. DescriptiveStatistics passes its stored window, so getPercentile (and toString) reordered the values: getValues no longer returned them in insertion order, and a rolling window then discarded the smallest value instead of the oldest. StatUtils.percentile reordered the caller's array. The Percentile class replaced in MATH-1671 worked on a copy.
|
Multiple calls to getPercentile will have significant performance overhead using a copy. StatUtils is not documented to be non-destructive to the array order. So an option is to document the current behaviour. If we keep this change to revert to Math3 behaviour the method should be documented to have performance overhead. However the DescriptiveStatistics is documented to return The previous Percentile implementation used a working array copy and maintained pivots to improve performance of the single-pivot quick select method. The current class could be modified to cache a working copy and a reference to input values and the [begin, length) to identify repeat calls. Feel free to examine this idea. This moves the copy operation from Quantile to be managed more efficiently by Percentile class. The simpler alternative is to document exactly what is happening on each call and provide the user with advice to get the values array once and call Quantile themselves with all desired percentiles in a single call. |
With the default percentile implementation, on master:
Statistics.PercentileandStatUtilsbuild their Commons StatisticsQuantilewithwithCopy(false), so it partially sorts the array it is given.DescriptiveStatistics.getPercentileevaluates it throughapply, which passes the stored window itself, so a read-only query reorders the data. From then ongetValues()andgetElement(i)no longer follow insertion order, and a rolling window discards the smallest value on the nextaddValuerather than the oldest, so later statistics are computed over the wrong values (mean 22.8 instead of 22.0 above).toString()reports the median and reorders the window the same way. ThePercentileclass replaced in MATH-1671 (fb1c36b) worked on a copy, so both call sites changed behaviour in that commit.Both quantiles now use
withCopy(true);Quantile.withDefaults()is in place, so the flag has to be explicit.DescriptiveStatisticsTest.testPercentileDoesNotReorderValues(also run bySynchronizedDescriptiveStatisticsTest) andStatUtilsTest.testPercentileDoesNotModifyInputfail on master and pass with the fix, and the defaultmvnbuild is green.