Skip to content

Commit 9424bd2

Browse files
authored
Fix change point detection for uncertain non-stationary distributions. (elastic#119578)
* Fix change point detection for uncertain non-stationary distributions. * Replace -1 by ChangeType.NO_CHANGE_POINT
1 parent a7d344e commit 9424bd2

File tree

4 files changed

+22
-7
lines changed

4 files changed

+22
-7
lines changed

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeDetector.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ private TestStats testTrendVs(TestStats H0, double[] values, double[] weights) {
189189
private TestStats testStepChangeVs(TestStats H0, double[] values, double[] weights, int[] candidateChangePoints) {
190190

191191
double vStep = Double.MAX_VALUE;
192-
int changePoint = -1;
192+
int changePoint = ChangeType.NO_CHANGE_POINT;
193193

194194
// Initialize running stats so that they are only missing the individual changepoint values
195195
RunningStats lowerRange = new RunningStats();
@@ -226,7 +226,7 @@ private TestStats testStepChangeVs(TestStats H0, double[] values, double[] weigh
226226
private TestStats testTrendChangeVs(TestStats H0, double[] values, double[] weights, int[] candidateChangePoints) {
227227

228228
double vChange = Double.MAX_VALUE;
229-
int changePoint = -1;
229+
int changePoint = ChangeType.NO_CHANGE_POINT;
230230

231231
// Initialize running stats so that they are only missing the individual changepoint values
232232
RunningStats lowerRange = new RunningStats();
@@ -349,7 +349,7 @@ private TestStats testDistributionChange(
349349
) {
350350

351351
double maxDiff = 0.0;
352-
int changePoint = -1;
352+
int changePoint = ChangeType.NO_CHANGE_POINT;
353353

354354
// Initialize running stats so that they are only missing the individual changepoint values
355355
RunningStats lowerRange = new RunningStats();
@@ -378,10 +378,12 @@ private TestStats testDistributionChange(
378378
// before we run the tests.
379379
SampleData sampleData = sample(values, weights, discoveredChangePoints);
380380
final double[] sampleValues = sampleData.values();
381-
final double[] sampleWeights = sampleData.weights();
382381

383382
double pValue = 1;
384383
for (int cp : sampleData.changePoints()) {
384+
if (cp == ChangeType.NO_CHANGE_POINT) {
385+
continue;
386+
}
385387
double[] x = Arrays.copyOfRange(sampleValues, 0, cp);
386388
double[] y = Arrays.copyOfRange(sampleValues, cp, sampleValues.length);
387389
double statistic = KOLMOGOROV_SMIRNOV_TEST.kolmogorovSmirnovStatistic(x, y);
@@ -451,7 +453,7 @@ private record TestStats(Type type, double pValue, double var, double nParams, i
451453
}
452454

453455
TestStats(Type type, double pValue, double var, double nParams, DataStats dataStats) {
454-
this(type, pValue, var, nParams, -1, dataStats);
456+
this(type, pValue, var, nParams, ChangeType.NO_CHANGE_POINT, dataStats);
455457
}
456458

457459
boolean accept(double pValueThreshold) {

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangePointAggregator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public InternalAggregation doReduce(InternalAggregations aggregations, Aggregati
4747
ChangeType change = ChangePointDetector.getChangeType(bucketValues);
4848

4949
ChangePointBucket changePointBucket = null;
50-
if (change.changePoint() >= 0) {
50+
if (change.changePoint() != ChangeType.NO_CHANGE_POINT) {
5151
changePointBucket = extractBucket(bucketsPaths()[0], aggregations, change.changePoint()).map(
5252
b -> new ChangePointBucket(b.getKey(), b.getDocCount(), b.getAggregations())
5353
).orElse(null);

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeType.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
*/
2222
public interface ChangeType extends NamedWriteable, NamedXContentObject {
2323

24+
int NO_CHANGE_POINT = -1;
25+
2426
default int changePoint() {
25-
return -1;
27+
return NO_CHANGE_POINT;
2628
}
2729

2830
default double pValue() {

x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/aggs/changepoint/ChangeDetectorTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import java.util.concurrent.atomic.AtomicInteger;
1818
import java.util.stream.DoubleStream;
1919

20+
import static org.hamcrest.Matchers.equalTo;
2021
import static org.hamcrest.Matchers.greaterThan;
2122
import static org.hamcrest.Matchers.instanceOf;
2223
import static org.hamcrest.Matchers.lessThan;
@@ -243,4 +244,14 @@ public void testProblemDistributionChange() {
243244
ChangeType type = new ChangeDetector(bucketValues).detect(0.05);
244245
assertThat(type, instanceOf(ChangeType.DistributionChange.class));
245246
}
247+
248+
public void testUncertainNonStationary() {
249+
MlAggsHelper.DoubleBucketValues bucketValues = new MlAggsHelper.DoubleBucketValues(
250+
null,
251+
new double[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 700, 735, 715 }
252+
);
253+
ChangeType type = new ChangeDetector(bucketValues).detect(0.01);
254+
assertThat(type, instanceOf(ChangeType.NonStationary.class));
255+
assertThat(((ChangeType.NonStationary) type).getTrend(), equalTo("increasing"));
256+
}
246257
}

0 commit comments

Comments
 (0)