/// <summary> /// Calculate a frequency distribution for the provided array of values. /// 1) The minimum and maximum values are found. /// 2) The resulting value range is divided into equal sized sub-ranges (categoryCount). /// 3) The number of values that fall into each category is determined. /// </summary> public static HistogramData BuildHistogramData(double[] valArr, int categoryCount) { // Determine min/max. MathArrayUtils.MinMax(valArr, out double min, out double max); // Note. each bucket's range has interval [low,high), i.e. samples exactly equal to 'high' // will fall into the next highest bucket. Therefore to prevent the maximum sample vAalue falling into the // last bucket by itself, we inflate the range by a small proportion so that the max value falls just below // the max range covered by the distribution. double range = (max - min) * 1.01; // Handle special case where the data series contains a single value. if (0.0 == range) { return(new HistogramData(min, max, 0.0, new int[] { valArr.Length })); } // Loop values and for each one increment the relevant category's frequency count. double incr = range / categoryCount; int[] frequencyArr = new int[categoryCount]; for (int i = 0; i < valArr.Length; i++) { frequencyArr[(int)((valArr[i] - min) / incr)]++; } return(new HistogramData(min, max, incr, frequencyArr)); }
private static void MinMax(UniformDistributionSampler sampler, int len) { // Alloc arrays and fill with uniform random noise. double[] a = new double[len]; sampler.Sample(a); // Calc results and compare. MinMax(a, out double expectedMin, out double expectedMax); MathArrayUtils.MinMax(a, out double actualMin, out double actualMax); Assert.AreEqual(expectedMin, actualMin, 1e-10); Assert.AreEqual(expectedMax, actualMax, 1e-10); }