如何克服 MannWhitney 判别法的缺陷
作者: moertel创建于 2020年8月11日更新于 2026年8月11日
标签enhancementcomponent/kayentano-lifecycle
点击此处展开单元测试
我们的推断是: 如果一个工程师看到此结果,他们肯定会停止部署并调查发生了什么。这个问题源于 MannWhitney 的工作方式。但是: 如何防止这种类型的假阴性呢?
test("Mann-Whitney 判别器测试: 变量性增加") {
val experimentData = Array(
10.0, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 17.0, 17.1, 17.2, 17.3, 17.4, 17.5, 17.6, 17.7
)
val controlData = Array(
1.0, 100.0, 4.0, 101.0, 5.0, 102.0, 6.0, 103.0, 7.0, 104.0, 8.0, 105.0, 9.0, 106.0, 17.0
)
val experimentMetric = Metric("pass-metric", experimentData, "canary")
val controlMetric = Metric("pass-metric", controlData, "baseline")
val classifier = new MannWhitneyClassifier(tolerance = 0.10, confLevel = 0.95)
val result = classifier.classify(controlMetric, experimentMetric, MetricDirection.Either)
assert(result.classification == Pass) // 从逻辑上来看,它不应该通过!
}我们的推断是: 如果一个工程师看到此结果,他们肯定会停止部署并调查发生了什么。这个问题源于 MannWhitney 的工作方式。但是: 如何防止这种类型的假阴性呢?

Case 2: 最初的波动随着时间的推移而消失
结果是 FAIL,但它应该是 PASS
点击此处展开单元测试 test("Mann-Whitney 判别器测试: 最初的波动随着时间的推移而消失") {
val experimentData = Array(
10.99, 10.991, 10.992, 10.993, 10.994, 10.995, 10.996, 11, 11.01, 11.02, 11.021, 11.023, 11.024, 11.025, 11.026
)
val controlData = Array(
2.1, 15.05, 2.2, 15.01, 2.3, 10.982, 11.011, 11, 10.989, 10.988, 10.987, 10.986, 10.985, 10.984, 10.983
)
val experimentMetric = Metric("pass-metric", experimentData, "canary")
val controlMetric = Metric("pass-metric", controlData, "baseline")
val classifier = new MannWhitneyClassifier(tolerance = 0.10, confLevel = 0.95)
val result =
…内容来源: spinnaker/spinnaker