def testUnitBootstrap(self): # The bootstrap depends upon random values to work; thus, we'll # only check that it's statistically close to a simulated value. # We set the seed to avoid flaky tests; this test will fail with # probability 0.05 otherwise. # Note this is an equivalent problem to the testBootstrap case, # we've just split some rows. np.random.seed(12345) x = [] y = [] for ii in range(1, 101): for _ in range(3): x.append(ii) y.append(ii) data = pd.DataFrame({"X": x, "Y": y}) metric = metrics.Mean("X") se_method = standard_errors.Bootstrap(100, unit="Y") output = core.Analyze(data).with_standard_errors(se_method).calculate( metric).run() bootstrap_se = output["mean(X) Bootstrap SE"].values[0] simulation_se = 2.88 epsilon = 0.41 # Two standard errors based on simulation. self.assertAlmostEqual(simulation_se, bootstrap_se, delta=epsilon)
def testNinetyFiveCIsWithComparison(self): data = pd.DataFrame({ "X": range(11), "Y": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1] }) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 0) se_method = standard_errors.Jackknife(confidence=0.95) output = core.Analyze(data).with_standard_errors( se_method).relative_to(comparison).calculate(metric).run() multiplier = scipy.stats.t.ppf(0.975, 10) correct_mean = 25 correct_buckets = [ 15., 16., 17., 18., 19., 25., 26., 27., 28., 29., 30. ] m = sum(correct_buckets) / len(correct_buckets) r = sum([(b - m)**2 for b in correct_buckets]) correct_sd = np.sqrt(r * (len(correct_buckets) - 1) / len(correct_buckets)) correct_lower = correct_mean - multiplier * correct_sd correct_upper = correct_mean + multiplier * correct_sd rowindex = pd.Index([1], name="Y") correct = pd.DataFrame( { "sum(X) Absolute Difference": correct_mean, "sum(X) Absolute Difference Jackknife CI-lower": correct_lower, "sum(X) Absolute Difference Jackknife CI-upper": correct_upper }, index=rowindex) self.assertTrue(output.equals(correct))
def testDoubleSEMethodDefinitionRaisesException(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5]}) se_method = standard_errors.Jackknife() with self.assertRaises(ValueError): core.Analyze(data).with_standard_errors( se_method).with_standard_errors(se_method)
def testDataframeRelativeToJackknife(self): df = pd.DataFrame({ "X": range(11), "Y": np.concatenate((np.zeros(6), np.ones(5))), "Z": np.concatenate((np.zeros(3), np.ones(8))) }) metric = metrics.Distribution("X", ["Z"]) se_method = standard_errors.Jackknife() output = core.Analyze(df).relative_to( comparisons.AbsoluteDifference( "Y", 0)).with_standard_errors(se_method).calculate(metric).run() correct = pd.DataFrame( np.array([[-0.2, 0.18100283490], [0.2, 0.18100283490]]), columns=[ "X Distribution Absolute Difference", "X Distribution Absolute Difference Jackknife SE" ], index=pd.MultiIndex(levels=[[1.], [0., 1.]], labels=[[0, 0], [0, 1]], names=["Y", "Z"])) self.assertTrue( all(output.index == correct.index) and all(output.columns == correct.columns) and np.all(abs(output.values - correct.values) < 1e-10))
def testRelativeToSplitJackknife(self): data = pd.DataFrame({ "X": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8], "Y": [1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3], "Z": [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1] }) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Z", 0) se_method = standard_errors.Jackknife() output = core.Analyze(data).split_by("Y").relative_to( comparison).with_standard_errors(se_method).calculate( metric).run() rowindex = pd.MultiIndex(levels=[[1, 2, 3], [1]], labels=[[0, 1, 2], [0, 0, 0]], names=["Y", "Z"]) correct = pd.DataFrame( np.array([[-3.0, np.sqrt(5 * np.var([0, -1, -2, -3, -4, -5]))], [-3.0, np.sqrt(5 * np.var([3, 2, 1, -8, -7, -6]))], [-3.0, np.sqrt(5 * np.var([6, 5, 4, -11, -10, -9]))]]), columns=("sum(X) Absolute Difference", "sum(X) Absolute Difference Jackknife SE"), index=rowindex) self.assertTrue(output.equals(correct))
def testShuffledDataframeRelativeToJackknife(self): # Same as test above, but also testing that reordering the data doesn't # change results, up to order. df = pd.DataFrame({ "X": range(11), "Y": np.concatenate((np.zeros(6), np.ones(5))), "Z": np.concatenate((np.zeros(3), np.ones(8))) }) metric = metrics.Distribution("X", ["Z"]) se_method = standard_errors.Jackknife() output = core.Analyze(df.iloc[np.random.permutation(11)]).relative_to( comparisons.AbsoluteDifference( "Y", 0)).with_standard_errors(se_method).calculate(metric).run() output = (output.reset_index().sort_values(by=["Y", "Z"]).set_index( ["Y", "Z"])) correct = pd.DataFrame( np.array([[-0.2, 0.18100283490], [0.2, 0.18100283490]]), columns=[ "X Distribution Absolute Difference", "X Distribution Absolute Difference Jackknife SE" ], index=pd.MultiIndex(levels=[[1.], [0., 1.]], labels=[[0, 0], [0, 1]], names=["Y", "Z"])) correct = (correct.reset_index().sort_values(by=["Y", "Z"]).set_index( ["Y", "Z"])) self.assertTrue( all(output.index == correct.index) and all(output.columns == correct.columns) and np.all(abs(output.values - correct.values) < 1e-10))
def testBootstrap(self): # The bootstrap depends upon random values to work; thus, we'll # only check that it's statistically close to the theoretical # value. # We set the seed to avoid flaky tests; this test will fail with # probability 0.05 otherwise. np.random.seed(12345) data = pd.DataFrame({"X": range(1, 101)}) metric = metrics.Mean("X") se_method = standard_errors.Bootstrap(100) output = core.Analyze(data).with_standard_errors(se_method).calculate( metric).run() bootstrap_se = output["mean(X) Bootstrap SE"].values[0] # Parameters based on the following R simulation # set.seed(12345) # library(bootstrap) # x <- 1:100 # estimates <- replicate(1000, sd(bootstrap(x, 100, mean)$thetastar)) # mean(estimates) # sd(estimates) simulation_se = 2.88 epsilon = 0.41 # Two standard errors based on simulation. self.assertAlmostEqual(simulation_se, bootstrap_se, delta=epsilon)
def testComparisonBaslineGivesError(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5], "Y": [1, 1, 1, 1, 1]}) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 0) with self.assertRaises(ValueError): core.Analyze(data).relative_to(comparison).calculate(metric).run()
def testSingleJackknifeBucketRaisesException(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5], "Y": [1, 1, 1, 1, 1]}) metric = metrics.Sum("X") se_method = standard_errors.Jackknife(unit="Y") with self.assertRaises(ValueError): core.Analyze(data).with_standard_errors(se_method).calculate( metric).run()
def testBadWhereRaisesError(self): data = pd.DataFrame({ "X": (1, 2, 3, 10, 20, 30, 100, 200, 300), "Y": (0, 1, 2, 3, 4, 5, 6, 7, 8) }) metric = metrics.Sum("X") with self.assertRaises(ValueError): core.Analyze(data).where("X + Y").calculate(metric).run()
def testNamingCalculations(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5]}) metric = metrics.Sum("X", name="X-Total") output = core.Analyze(data).calculate(metric).run() correct = pd.DataFrame(np.array([[15]]), columns=["X-Total"]) self.assertTrue(output.equals(correct))
def testMultipleCalculations(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5]}) output = core.Analyze(data).calculate( [metrics.Sum("X"), metrics.Mean("X")]).run() correct = pd.DataFrame(np.array([[15, 3.0]]), columns=["sum(X)", "mean(X)"]) correct[["sum(X)"]] = correct[["sum(X)"]].astype(int) self.assertTrue(output.equals(correct))
def testWhere(self): data = pd.DataFrame({ "X": (1, 2, 3, 10, 20, 30, 100, 200, 300), "Y": (0, 1, 2, 3, 4, 5, 6, 7, 8) }) metric = metrics.Sum("X") output = core.Analyze(data).where("Y >= 4").calculate(metric).run() correct = pd.DataFrame(np.array([[650]]), columns=["sum(X)"]) self.assertTrue(output.equals(correct))
def testJackknife(self): data = pd.DataFrame({"X": range(11)}) metric = metrics.Sum("X") se_method = standard_errors.Jackknife() output = core.Analyze(data).with_standard_errors(se_method).calculate( metric).run() correct = pd.DataFrame(np.array([[55.0, 10.0]]), columns=("sum(X)", "sum(X) Jackknife SE")) self.assertTrue(output.equals(correct))
def testJackknifeBadSample(self): data = pd.DataFrame({"X": range(22), "Y": ([0] * 11) + ([1] * 11)}) metric = metrics.Sum("X") se_method = standard_errors.Jackknife() output = core.Analyze(data).split_by("Y").with_standard_errors( se_method).calculate(metric).run() correct = pd.DataFrame(np.array([[55.0, 10.0], [176.0, 10.0]]), columns=("sum(X)", "sum(X) Jackknife SE")) correct.index.name = "Y" self.assertTrue(output.equals(correct))
def testSplitBy(self): data = pd.DataFrame({ "X": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], "Y": [1, 1, 2, 2, 3, 3, 4, 4, 5, 5] }) metric = metrics.Sum("X") output = core.Analyze(data).calculate(metric).split_by("Y").run() correct = pd.DataFrame({ "sum(X)": [1, 5, 9, 13, 17], "Y": [1, 2, 3, 4, 5] }) correct = correct.set_index("Y") self.assertTrue(output.equals(correct))
def testJackknifeRatio(self): data = pd.DataFrame({"X": [1, 2, 3, 4], "Y": [4, 3, 2, 1]}) metric = metrics.Ratio("X", "Y") se_method = standard_errors.Jackknife() output = core.Analyze(data).with_standard_errors(se_method).calculate( metric).run() estimates = np.array([9 / 6, 8 / 7, 7 / 8, 6 / 9]) rss = ((estimates - estimates.mean())**2).sum() se = np.sqrt(rss * 3 / 4) correct = pd.DataFrame([[1.0, se]], columns=("X/Y", "X/Y Jackknife SE")) self.assertTrue(output.equals(correct))
def testSplitJackknife(self): data = pd.DataFrame({ "X": np.array([range(11) + [5] * 10]).flatten(), "Y": np.array([[0] * 11 + [1] * 10]).flatten() }) metric = metrics.Sum("X") se_method = standard_errors.Jackknife() output = core.Analyze(data).split_by("Y").with_standard_errors( se_method).calculate(metric).run() rowindex = pd.Index([0, 1], name="Y") correct = pd.DataFrame(np.array([[55.0, 10.0], [50.0, 0.0]]), columns=("sum(X)", "sum(X) Jackknife SE"), index=rowindex) self.assertTrue(output.equals(correct))
def testRelativeToJackknifeSingleComparisonBaselineSecond(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5, 6], "Y": [0, 0, 0, 1, 1, 1]}) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 1) se_method = standard_errors.Jackknife() output = core.Analyze(data).relative_to( comparison).with_standard_errors(se_method).calculate( metric).run() rowindex = pd.Index([0], name="Y") correct = pd.DataFrame( np.array([[-9.0, np.sqrt(5 * np.var([12, 11, 10, 5, 4, 3]))]]), columns=("sum(X) Absolute Difference", "sum(X) Absolute Difference Jackknife SE"), index=rowindex) self.assertTrue(output.equals(correct))
def testMultipleSplitBy(self): data = pd.DataFrame({ "X": [4, 5, 6, 7, 0, 1, 2, 3], "Y": [1, 1, 1, 1, 0, 0, 0, 0], "Z": [0, 0, 1, 1, 0, 0, 1, 1] }) metric = metrics.Sum("X") output = core.Analyze(data).split_by(["Y", "Z"]).calculate(metric).run() correct = pd.DataFrame({ "sum(X)": [1, 5, 9, 13], "Y": [0, 0, 1, 1], "Z": [0, 1, 0, 1] }) correct = correct.set_index(["Y", "Z"]) self.assertTrue(output.equals(correct))
def testSortFalse(self): data = pd.DataFrame({ "X": [6, 5, 4, 7, 0, 1, 2, 3], "Y": [1, 1, 1, 1, 0, 0, 0, 0], "Z": [1, 0, 0, 1, 0, 0, 1, 1] }) metric = metrics.Sum("X") output = core.Analyze(data).split_by( ["Y", "Z"]).calculate(metric).run(sort=False) correct = pd.DataFrame({ "sum(X)": [13, 9, 1, 5], "Y": [1, 1, 0, 0], "Z": [1, 0, 0, 1] }) correct = correct.set_index(["Y", "Z"]) self.assertTrue(output.equals(correct))
def testRelativeTo(self): data = pd.DataFrame({ "X": [1, 2, 3, 10, 20, 30, 100, 200, 300], "Y": [0, 0, 0, 1, 1, 1, 2, 2, 2] }) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 0) output = core.Analyze(data).relative_to(comparison).calculate( metric).run() correct = pd.DataFrame({ "sum(X) Absolute Difference": [60 - 6, 600 - 6], "Y": [1, 2] }) correct = correct.set_index("Y") self.assertTrue(output.equals(correct))
def testMultipleCalculationsRelativeTo(self): data = pd.DataFrame({ "X": (1, 2, 3, 10, 20, 30, 100, 200, 300), "Y": (0, 1, 2, 3, 4, 5, 6, 7, 8), "Experiment": ("Control", "Control", "Control", "Exp1", "Exp1", "Exp1", "Exp2", "Exp2", "Exp2") }) comparison = comparisons.AbsoluteDifference("Experiment", "Control") output = core.Analyze(data).relative_to(comparison).calculate( (metrics.Sum("X"), metrics.Sum("Y"))).run() correct = pd.DataFrame( { "sum(X) Absolute Difference": (60 - 6, 600 - 6), "sum(Y) Absolute Difference": (12 - 3, 21 - 3) }, index=pd.Index(("Exp1", "Exp2"), name="Experiment")) self.assertTrue(output.equals(correct))
def testRelativeToSplitsWithNoAlternativeGivesNaN(self): data = pd.DataFrame({ "X": [1, 2, 3, 4], "Y": [0, 0, 0, 1], "Z": [0, 0, 1, 1] }) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 0) output = core.Analyze(data).split_by("Z").relative_to( comparison).calculate(metric).run() correct = pd.DataFrame({ "sum(X) Absolute Difference": [np.nan, 4 - 3], "Z": [0, 1], "Y": [1, 1] }) correct = correct.set_index(["Z", "Y"]) self.assertTrue(output.equals(correct))
def testFiftyCIs(self): data = pd.DataFrame({"X": range(11)}) metric = metrics.Sum("X") se_method = standard_errors.Jackknife(confidence=0.50) output = core.Analyze(data).with_standard_errors(se_method).calculate( metric).run() multiplier = scipy.stats.t.ppf(0.75, 10) correct_sd = 10.0 correct_mean = 55.0 correct_lower = correct_mean - multiplier * correct_sd correct_upper = correct_mean + multiplier * correct_sd correct = pd.DataFrame(np.array( [[correct_mean, correct_lower, correct_upper]]), columns=("sum(X)", "sum(X) Jackknife CI-lower", "sum(X) Jackknife CI-upper")) self.assertTrue(output.equals(correct))
def testRelativeToSplit(self): data = pd.DataFrame({ "X": [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8], "Y": [0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2], "Z": [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] }) metric = metrics.Sum("X") comparison = comparisons.AbsoluteDifference("Y", 0) output = core.Analyze(data).split_by("Z").relative_to( comparison).calculate(metric).run() correct = pd.DataFrame({ "sum(X) Absolute Difference": [13 - 5, 23 - 5, 14 - 4, 22 - 4], "Z": [0, 0, 1, 1], "Y": [1, 2, 1, 2] }) correct = correct.set_index(["Z", "Y"]) self.assertTrue(output.equals(correct))
def testSplitDataframe(self): df = pd.DataFrame({ "X": range(11), "Y": np.concatenate((np.zeros(6), np.ones(5))), "Z": np.concatenate((np.zeros(3), np.ones(8))) }) metric = metrics.Distribution("X", ["Z"]) output = core.Analyze(df).split_by(["Y"]).calculate(metric).run() correct = pd.DataFrame(np.array([0.2, 0.8, 0.0, 1.0]), columns=["X Distribution"], index=pd.MultiIndex(levels=[[0.0, 1.0], [0.0, 1.0]], labels=[[0, 0, 1, 1], [0, 1, 0, 1]], names=["Y", "Z"])) self.assertTrue( all(output.index == correct.index) and all(output.columns == correct.columns) and np.all(abs(output.values - correct.values) < 1e-10))
def testDataframeJackknife(self): df = pd.DataFrame({ "X": range(11), "Y": np.concatenate((np.zeros(6), np.ones(5))), "Z": np.concatenate((np.zeros(3), np.ones(8))) }) metric = metrics.Distribution("X", ["Z"]) se_method = standard_errors.Jackknife("Y") output = core.Analyze(df).with_standard_errors(se_method).calculate( metric).run() correct = pd.DataFrame( np.array([[3 / 55., np.sqrt(((3 / 15. - 0.1)**2 + 0.1**2) / 2.)], [52 / 55., np.sqrt(((12 / 15. - 0.9)**2 + 0.1**2) / 2.)]]), columns=("X Distribution", "X Distribution Jackknife SE"), index=pd.Index([0., 1.], name="Z")) self.assertTrue( all(output.index == correct.index) and all(output.columns == correct.columns) and np.all(abs(output.values - correct.values) < 1e-10))
def testDoubleComparisonDefinitionRaisesException(self): data = pd.DataFrame({"X": [1, 2, 3, 4, 5]}) comparison = comparisons.AbsoluteDifference("X", 0) with self.assertRaises(ValueError): core.Analyze(data).relative_to(comparison).relative_to(comparison)