NumericalFeaturesStatistics { private synchronized Long2ObjectMap<Binning> buildBinning() { Long2ObjectMap<Binning> newBinnings = new Long2ObjectLinkedOpenHashMap<>(); for (long index : digests.keySet()) { TDigest digest = digests.get(index); double min = minimums.get(index); Binning binning = buildBinning(digest, min); newBinnings.put(index, binning); } return newBinnings; } NumericalFeaturesStatistics(); synchronized void finishCalculateDigests(StatisticsWorkHandler handler); Long2ObjectMap<Binning> binnings(); synchronized Long2ObjectMap<Double2DoubleMap> buildHistograms(); Long2ObjectMap<Double2DoubleMap> histograms(); void logFeaturesStatistics(); @Inject NumericalFeaturesStatistics percentsHistogramStep(
            @Named("percentsBinningStep") double percentsHistogramStep);  }
@Test public void testBuildBinning() { TDigest digest = new TDigest(100); for (int i = 0; i < 1000; i++) { digest.add(ThreadLocalRandom.current().nextDouble()); } NumericalFeaturesStatistics st = new NumericalFeaturesStatistics() .percentsHistogramStep(0.01); Binning binning = st.buildBinning(digest, 0.); assertEquals(0, binning.getInsertionPoint(0.)); assertEquals(-1, binning.getInsertionPoint(-0.1)); assertEquals(99, binning.getInsertionPoint(1.)); assertEquals(99, binning.getInsertionPoint(Double.MAX_VALUE)); int middleInsertion = binning.getInsertionPoint(0.5); assertTrue("middleInsertion is " + middleInsertion, middleInsertion > 45 && middleInsertion < 55); int quarterInsertion = binning.getInsertionPoint(0.25); assertTrue("quarterInsertion is " + quarterInsertion, quarterInsertion > 20 && quarterInsertion < 30); int thirdQuarterInsertion = binning.getInsertionPoint(0.75); assertTrue("thirdQuarterInsertion is " + thirdQuarterInsertion, thirdQuarterInsertion > 70 && thirdQuarterInsertion < 80); }