/** * Computes an alpha trimmed mean upon the current region of the current function. Note that this * method uses memory to make a copy of the input values. Larger input regions might require a lot * of memory. * * @param alpha A number between 0 and 0.5 specifying the proportion of samples to ignore on each * end. * @return The measured value */ public double alphaTrimmedMean(double alpha) { if ((alpha < 0) || (alpha >= 0.5)) throw new IllegalArgumentException("alpha value must be >= 0 and < 0.5"); T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } values.sortValues(); double tailSize = alpha * values.size(); // can we avoid interpolation? if (tailSize == Math.floor(tailSize)) { // yes, trim count is exactly an integer return calcTrimmedMean(values, (int) tailSize); } // no, trim count is a float value // calc two trimmed means and interpolate to find the value between them double mean1 = calcTrimmedMean(values, (int) Math.floor(tailSize)); double mean2 = calcTrimmedMean(values, (int) Math.ceil(tailSize)); double fraction = tailSize - Math.floor(tailSize); double interpolation = ((1 - fraction) * mean1) + (fraction * mean2); return interpolation; }
/** * Computes a trimmed mean upon the current region of the current function. Note that this method * uses memory to make a copy of the input values. Larger input regions might require a lot of * memory. * * @param halfTrimSize The number of samples to ignore from each end of the data * @return The measured value */ public double trimmedMean(int halfTrimSize) { T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } values.sortValues(); return calcTrimmedMean(values, halfTrimSize); }
private double calcTrimmedMean(PrimitiveDoubleArray vals, int halfTrim) { final int trimSize = halfTrim * 2; final int numElements = vals.size(); if (numElements <= trimSize) throw new IllegalArgumentException( "number of samples must be greater than number of trimmed values"); final int top = numElements - halfTrim; double sum = 0; for (int i = halfTrim; i < top; i++) { sum += vals.get(i); } return sum / (numElements - trimSize); }
/** * Resets the StatCalculator to work with a new function and/or region. The calculator does the * minimum amount of reinitialization. * * @param newFunc The new {@link Function} to use for obtaining sample values * @param newRegion The new {@link PointSet} region over which to gather samples */ public void reset(Function<long[], T> newFunc, PointSet newRegion) { func = newFunc; if (newRegion == region) { iter.reset(); } else { region = newRegion; iter = region.iterator(); } values.clear(); }
/** * Computes the median upon the current region of the current function. Note that this method uses * memory to make a copy of the input values. Larger input regions might require a lot of memory. * * @return The measured value */ public double median() { T tmp = func.createOutput(); values.clear(); iter.reset(); while (iter.hasNext()) { long[] pos = iter.next(); func.compute(pos, tmp); values.add(tmp.getRealDouble()); } final int numElements = values.size(); if (numElements <= 0) throw new IllegalArgumentException("number of samples must be greater than 0"); values.sortValues(); // odd number of elements if ((numElements % 2) == 1) return values.get(numElements / 2); // else an even number of elements double value1 = values.get((numElements / 2) - 1); double value2 = values.get((numElements / 2)); return (value1 + value2) / 2; }