@Test public void estimateRateDifference() throws Exception { Estimate output = testStats95.estimateRateDifference(5, 2, 4, 3); assertThat("2/5 - 3/4 = -0.35", output.getEstimate(), IsCloseTo.closeTo(-0.35, precision)); assertThat("check lower bound", output.getLowerBound(), IsCloseTo.closeTo(-0.9537039, precision)); assertThat("check upper bound", output.getUpperBound(), IsCloseTo.closeTo(0.2537039, precision)); output = testStats95.estimateRateDifference(500, 200, 400, 300); assertThat("200/500 - 300/400 = -0.35", output.getEstimate(), IsCloseTo.closeTo(-0.35, precision)); assertThat("check lower bound", output.getLowerBound(), IsCloseTo.closeTo(-0.4103704, precision)); assertThat("check upper bound", output.getUpperBound(), IsCloseTo.closeTo(-0.2896296, precision)); output = testStats95.estimateRateDifference(1, 1, 0, 0); assertThat("0 impressions returns NaN", output.getEstimate(), is(NaN)); assertThat("0 impressions returns NaN", output.getLowerBound(), is(NaN)); assertThat("0 impressions returns NaN", output.getUpperBound(), is(NaN)); output = testStats95.estimateRateDifference(0, 0, 1, 1); assertThat("0 impressions returns NaN", output.getEstimate(), is(NaN)); assertThat("0 impressions returns NaN", output.getLowerBound(), is(NaN)); assertThat("0 impressions returns NaN", output.getUpperBound(), is(NaN)); }
@Override public Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1, final long number_impressions_2, final long number_actions_2) { inputValidation(number_impressions_1, number_actions_1, number_impressions_2); if (number_actions_2 < 0) { throw new IllegalArgumentException("Number of unique actions must be nonnegative."); } if (number_actions_2 > number_impressions_2) { throw new IllegalArgumentException("Number of unique actions cannot exceed number of unique impressions."); } double zval = DecisionAdjuster.scaledZ(confidenceLevel, maxDecisions); double rate_1 = 1.0 * number_actions_1 / number_impressions_1; double rate_2 = 1.0 * number_actions_2 / number_impressions_2; double rate_diff = rate_1 - rate_2; double confint = zval * sqrt(rate_1 * (1 - rate_1) / number_impressions_1 + rate_2 * (1 - rate_2) / number_impressions_2); return new Estimate.Builder().withEstimate(rate_diff) .withLowerBound(rate_diff - confint) .withUpperBound(rate_diff + confint).build(); }
NormalApproxMetric extends BinomialMetric { @Override public Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1, final long number_impressions_2, final long number_actions_2) { inputValidation(number_impressions_1, number_actions_1, number_impressions_2); if (number_actions_2 < 0) { throw new IllegalArgumentException("Number of unique actions must be nonnegative."); } if (number_actions_2 > number_impressions_2) { throw new IllegalArgumentException("Number of unique actions cannot exceed number of unique impressions."); } double zval = DecisionAdjuster.scaledZ(confidenceLevel, maxDecisions); double rate_1 = 1.0 * number_actions_1 / number_impressions_1; double rate_2 = 1.0 * number_actions_2 / number_impressions_2; double rate_diff = rate_1 - rate_2; double confint = zval * sqrt(rate_1 * (1 - rate_1) / number_impressions_1 + rate_2 * (1 - rate_2) / number_impressions_2); return new Estimate.Builder().withEstimate(rate_diff) .withLowerBound(rate_diff - confint) .withUpperBound(rate_diff + confint).build(); } }
NormalApproxMetric extends BinomialMetric { @Override public Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1, final long number_impressions_2, final long number_actions_2) { inputValidation(number_impressions_1, number_actions_1, number_impressions_2); if (number_actions_2 < 0) { throw new IllegalArgumentException("Number of unique actions must be nonnegative."); } if (number_actions_2 > number_impressions_2) { throw new IllegalArgumentException("Number of unique actions cannot exceed number of unique impressions."); } double zval = DecisionAdjuster.scaledZ(confidenceLevel, maxDecisions); double rate_1 = 1.0 * number_actions_1 / number_impressions_1; double rate_2 = 1.0 * number_actions_2 / number_impressions_2; double rate_diff = rate_1 - rate_2; double confint = zval * sqrt(rate_1 * (1 - rate_1) / number_impressions_1 + rate_2 * (1 - rate_2) / number_impressions_2); return new Estimate.Builder().withEstimate(rate_diff) .withLowerBound(rate_diff - confint) .withUpperBound(rate_diff + confint).build(); } NormalApproxMetric(final double conf_level);  NormalApproxMetric(final double conf_level, final double max_decisions); }
NormalApproxMetric extends BinomialMetric { @Override public Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1, final long number_impressions_2, final long number_actions_2) { inputValidation(number_impressions_1, number_actions_1, number_impressions_2); if (number_actions_2 < 0) { throw new IllegalArgumentException("Number of unique actions must be nonnegative."); } if (number_actions_2 > number_impressions_2) { throw new IllegalArgumentException("Number of unique actions cannot exceed number of unique impressions."); } double zval = DecisionAdjuster.scaledZ(confidenceLevel, maxDecisions); double rate_1 = 1.0 * number_actions_1 / number_impressions_1; double rate_2 = 1.0 * number_actions_2 / number_impressions_2; double rate_diff = rate_1 - rate_2; double confint = zval * sqrt(rate_1 * (1 - rate_1) / number_impressions_1 + rate_2 * (1 - rate_2) / number_impressions_2); return new Estimate.Builder().withEstimate(rate_diff) .withLowerBound(rate_diff - confint) .withUpperBound(rate_diff + confint).build(); } NormalApproxMetric(final double conf_level);  NormalApproxMetric(final double conf_level, final double max_decisions); @Override Estimate estimateRate(final long number_impressions, final long number_actions); @Override Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1,
                                           final long number_impressions_2, final long number_actions_2); @Override DistinguishableEffectSize distinguishableEffectSizes(final long number_impressions_1,
                                                                final long number_actions_1,
                                                                final long number_impressions_2,
                                                                final long number_actions_2); @Override Double fractionOfData(final long number_impressions_1, final long number_actions_1,
                                 final long number_impressions_2, final long number_actions_2,
                                 final double effect_size); @Override Long predictedDataNeeded(final double rate, final double allocation_percent_1,
                                    final double allocation_percent_2, final double effect_size); }
NormalApproxMetric extends BinomialMetric { @Override public Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1, final long number_impressions_2, final long number_actions_2) { inputValidation(number_impressions_1, number_actions_1, number_impressions_2); if (number_actions_2 < 0) { throw new IllegalArgumentException("Number of unique actions must be nonnegative."); } if (number_actions_2 > number_impressions_2) { throw new IllegalArgumentException("Number of unique actions cannot exceed number of unique impressions."); } double zval = DecisionAdjuster.scaledZ(confidenceLevel, maxDecisions); double rate_1 = 1.0 * number_actions_1 / number_impressions_1; double rate_2 = 1.0 * number_actions_2 / number_impressions_2; double rate_diff = rate_1 - rate_2; double confint = zval * sqrt(rate_1 * (1 - rate_1) / number_impressions_1 + rate_2 * (1 - rate_2) / number_impressions_2); return new Estimate.Builder().withEstimate(rate_diff) .withLowerBound(rate_diff - confint) .withUpperBound(rate_diff + confint).build(); } NormalApproxMetric(final double conf_level);  NormalApproxMetric(final double conf_level, final double max_decisions); @Override Estimate estimateRate(final long number_impressions, final long number_actions); @Override Estimate estimateRateDifference(final long number_impressions_1, final long number_actions_1,
                                           final long number_impressions_2, final long number_actions_2); @Override DistinguishableEffectSize distinguishableEffectSizes(final long number_impressions_1,
                                                                final long number_actions_1,
                                                                final long number_impressions_2,
                                                                final long number_actions_2); @Override Double fractionOfData(final long number_impressions_1, final long number_actions_1,
                                 final long number_impressions_2, final long number_actions_2,
                                 final double effect_size); @Override Long predictedDataNeeded(final double rate, final double allocation_percent_1,
                                    final double allocation_percent_2, final double effect_size);  }