mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
docs(analyze): name the tests the tool actually runs
The --paired flag advertised the signed-rank, two comments and a test message still said rank-sum, and nothing said what rankSum is doing in the tree now that no campaign reaches it.
This commit is contained in:
1 parent
1008402558
commit
dd625de068
4 files changed
+11
-6
No files matched your search
@@ -320,7 +320,7 @@ func writeCleanCampaign(t *testing.T, directory, name string, budget, steps, run
|
|||||||
|
|
||||||
// Arms censored at different budgets are not on the same clock: every clean run
|
// Arms censored at different budgets are not on the same clock: every clean run
|
||||||
// of the wider arm outranks every clean run of the narrower one whatever the
|
// of the wider arm outranks every clean run of the narrower one whatever the
|
||||||
// app did, so the rank-sum and the paired test reach a foregone conclusion the
|
// app did, so the pairwise and the paired test reach a foregone conclusion the
|
||||||
// log-rank in the same report contradicts. groupArms already refuses this
|
// log-rank in the same report contradicts. groupArms already refuses this
|
||||||
// within one arm, and comparing across arms is the same hazard.
|
// within one arm, and comparing across arms is the same hazard.
|
||||||
func TestRun_RefusesToCompareArmsCensoredAtDifferentBudgets(t *testing.T) {
|
func TestRun_RefusesToCompareArmsCensoredAtDifferentBudgets(t *testing.T) {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func run(arguments []string, stdout, stderr io.Writer) error {
|
|||||||
flagSet.Var(&directories, "campaign", "campaign directory to read; repeat for more, or pass them as arguments")
|
flagSet.Var(&directories, "campaign", "campaign directory to read; repeat for more, or pass them as arguments")
|
||||||
flagSet.StringVar(&jsonPath, "json", "", "write the machine-readable summary here, or - for stdout")
|
flagSet.StringVar(&jsonPath, "json", "", "write the machine-readable summary here, or - for stdout")
|
||||||
flagSet.StringVar(&question, "question", "", "the research question these campaigns answer; Holm corrects within one invocation, and this records which family that was")
|
flagSet.StringVar(&question, "question", "", "the research question these campaigns answer; Holm corrects within one invocation, and this records which family that was")
|
||||||
flagSet.BoolVar(&paired, "paired", false, "the two arms ran the same seeds: contrast them seed by seed with the Wilcoxon signed-rank test instead of the rank-sum test")
|
flagSet.BoolVar(&paired, "paired", false, "the two arms ran the same seeds: contrast them seed by seed with the sign test instead of pooling them into two independent samples")
|
||||||
if err := flagSet.Parse(arguments); err != nil {
|
if err := flagSet.Parse(arguments); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,12 +311,12 @@ func survivalAtStep(curve []survivalPoint, step float64) (float64, bool) {
|
|||||||
func TestPlanted_TrueNullIsNotCalledSignificantAboveItsLevel(t *testing.T) {
|
func TestPlanted_TrueNullIsNotCalledSignificantAboveItsLevel(t *testing.T) {
|
||||||
const replicates = 300
|
const replicates = 300
|
||||||
model := plantedModel{Hazard: 0.01, Budget: 400}
|
model := plantedModel{Hazard: 0.01, Budget: 400}
|
||||||
rejectedByRankSum, rejectedByLogRank := 0, 0
|
rejectedByGehan, rejectedByLogRank := 0, 0
|
||||||
for replicate := 0; replicate < replicates; replicate++ {
|
for replicate := 0; replicate < replicates; replicate++ {
|
||||||
first, second := plantTwoArms(t, int64(1000+replicate), 30, model, model)
|
first, second := plantTwoArms(t, int64(1000+replicate), 30, model, model)
|
||||||
result := analyseCampaigns(t, first, second)
|
result := analyseCampaigns(t, first, second)
|
||||||
if result.Pairwise[0].PValue < 0.05 {
|
if result.Pairwise[0].PValue < 0.05 {
|
||||||
rejectedByRankSum++
|
rejectedByGehan++
|
||||||
}
|
}
|
||||||
if result.LogRank.PValue < 0.05 {
|
if result.LogRank.PValue < 0.05 {
|
||||||
rejectedByLogRank++
|
rejectedByLogRank++
|
||||||
@@ -325,7 +325,7 @@ func TestPlanted_TrueNullIsNotCalledSignificantAboveItsLevel(t *testing.T) {
|
|||||||
// Three standard errors around 0.05 at 300 replicates is 0.05 +/- 0.038.
|
// Three standard errors around 0.05 at 300 replicates is 0.05 +/- 0.038.
|
||||||
// The lower bound is asserted too: a test that never rejects has bought its
|
// The lower bound is asserted too: a test that never rejects has bought its
|
||||||
// level by losing the power the experiment is sized for.
|
// level by losing the power the experiment is sized for.
|
||||||
for name, rejected := range map[string]int{"rank-sum": rejectedByRankSum, "log-rank": rejectedByLogRank} {
|
for name, rejected := range map[string]int{"gehan": rejectedByGehan, "log-rank": rejectedByLogRank} {
|
||||||
rate := float64(rejected) / replicates
|
rate := float64(rejected) / replicates
|
||||||
if rate > 0.09 || rate < 0.015 {
|
if rate > 0.09 || rate < 0.015 {
|
||||||
t.Errorf("%s called a true null significant in %.1f%% of %d replicates, want about 5%%",
|
t.Errorf("%s called a true null significant in %.1f%% of %d replicates, want about 5%%",
|
||||||
@@ -350,7 +350,7 @@ func TestPlanted_TrueNullUnderHeavyCensoringKeepsItsLevel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rate := float64(rejected) / replicates; rate > 0.09 {
|
if rate := float64(rejected) / replicates; rate > 0.09 {
|
||||||
t.Errorf("rank-sum called a true null significant in %.1f%% of %d replicates under heavy censoring, want at most about 5%%",
|
t.Errorf("gehan called a true null significant in %.1f%% of %d replicates under heavy censoring, want at most about 5%%",
|
||||||
100*rate, replicates)
|
100*rate, replicates)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ func vargaDelaneyA12(first, second []float64) float64 {
|
|||||||
// W. The exact null distribution is used when there are no ties and both
|
// W. The exact null distribution is used when there are no ties and both
|
||||||
// samples are small; otherwise the normal approximation is used with the
|
// samples are small; otherwise the normal approximation is used with the
|
||||||
// continuity correction and the tie correction to the variance.
|
// continuity correction and the tie correction to the variance.
|
||||||
|
//
|
||||||
|
// It takes plain numbers, so it cannot be given campaign runs, where a clean one
|
||||||
|
// carries a bound and not a value. What it is here for is the uncensored case
|
||||||
|
// the pipeline's comparison has to reproduce: this implementation is checked
|
||||||
|
// against R on a published sample, and gehanTest is checked against this one.
|
||||||
func rankSum(first, second []float64) rankSumResult {
|
func rankSum(first, second []float64) rankSumResult {
|
||||||
firstSize, secondSize := len(first), len(second)
|
firstSize, secondSize := len(first), len(second)
|
||||||
result := rankSumResult{
|
result := rankSumResult{
|
||||||
|
|||||||
Reference in new issue
Block a user