Skip to content

Commit 214c4e8

Browse files
committed
Huge checkin for Anomaly / AnomalyLikelihood functionality
1 parent b993177 commit 214c4e8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2905
-101
lines changed

EclipseFormatRules.xml

+295
Large diffs are not rendered by default.

src/main/java/org/numenta/nupic/Connections.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ public double getPermanenceDecrement() {
14981498
* @param cells
14991499
* @return
15001500
*/
1501-
public List<Integer> asCellIndexes(Collection<Cell> cells) {
1501+
public static List<Integer> asCellIndexes(Collection<Cell> cells) {
15021502
List<Integer> ints = new ArrayList<Integer>();
15031503
for(Cell cell : cells) {
15041504
ints.add(cell.getIndex());
@@ -1514,7 +1514,7 @@ public List<Integer> asCellIndexes(Collection<Cell> cells) {
15141514
* @param columns
15151515
* @return
15161516
*/
1517-
public List<Integer> asColumnIndexes(Collection<Column> columns) {
1517+
public static List<Integer> asColumnIndexes(Collection<Column> columns) {
15181518
List<Integer> ints = new ArrayList<Integer>();
15191519
for(Column col : columns) {
15201520
ints.add(col.getIndex());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package org.numenta.nupic.algorithms;
2+
3+
import java.util.Map;
4+
5+
import org.numenta.nupic.util.ArrayUtils;
6+
7+
8+
public abstract class Anomaly {
9+
/** Modes to use for factory creation method */
10+
public enum Mode { PURE, LIKELIHOOD, WEIGHTED };
11+
12+
// Instantiation keys
13+
public final static int VALUE_NONE = -1;
14+
public final static String KEY_MODE = "mode";
15+
public final static String KEY_LEARNING_PERIOD = "claLearningPeriod";
16+
public final static String KEY_ESTIMATION_SAMPLES = "estimationSamples";
17+
public final static String KEY_MOVING_AVG = "useMovingAverage";
18+
public final static String KEY_WINDOW_SIZE = "windowSize";
19+
public final static String KEY_IS_WEIGHTED = "isWeighted";
20+
21+
// Computational argument keys
22+
public final static String KEY_MEAN = "mean";
23+
public final static String KEY_STDEV = "stdev";
24+
public final static String KEY_VARIANCE = "variance";
25+
26+
protected MovingAverage movingAverage;
27+
28+
protected boolean useMovingAverage;
29+
30+
/**
31+
* Constructs a new {@code Anomaly}
32+
*/
33+
public Anomaly() {
34+
this(false, -1);
35+
}
36+
37+
/**
38+
* Constructs a new {@code Anomaly}
39+
*
40+
* @param useMovingAverage indicates whether to apply and store a moving average
41+
* @param windowSize size of window to average over
42+
*/
43+
protected Anomaly(boolean useMovingAverage, int windowSize) {
44+
this.useMovingAverage = useMovingAverage;
45+
if(this.useMovingAverage) {
46+
if(windowSize < 1) {
47+
throw new IllegalArgumentException(
48+
"Window size must be > 0, when using moving average.");
49+
}
50+
movingAverage = new MovingAverage(null, windowSize);
51+
}
52+
}
53+
54+
/**
55+
* Returns an {@code Anomaly} configured to execute the type
56+
* of calculation specified by the {@link Mode}, and whether or
57+
* not to apply a moving average.
58+
*
59+
* Must have one of "MODE" = {@link Mode#LIKELIHOOD}, {@link Mode#PURE}, {@link Mode#WEIGHTED}
60+
*
61+
* @param p Map
62+
* @return
63+
*/
64+
public static Anomaly create(Map<String, Object> params) {
65+
boolean useMovingAvg = (boolean)params.getOrDefault(KEY_MOVING_AVG, false);
66+
int windowSize = (int)params.getOrDefault(KEY_WINDOW_SIZE, -1);
67+
if(useMovingAvg && windowSize < 1) {
68+
throw new IllegalArgumentException("windowSize must be > 0, when using moving average.");
69+
}
70+
71+
Mode mode = (Mode)params.get(KEY_MODE);
72+
if(mode == null) {
73+
throw new IllegalArgumentException("MODE cannot be null.");
74+
}
75+
76+
switch(mode) {
77+
case PURE: return new Anomaly(useMovingAvg, windowSize) {
78+
@Override
79+
public double compute(int[] activeColumns, int[] predictedColumns, Object inputValue, long timestamp) {
80+
double retVal = computeRawAnomalyScore(activeColumns, predictedColumns);
81+
if(this.useMovingAverage) {
82+
retVal = movingAverage.next(retVal);
83+
}
84+
return retVal;
85+
}};
86+
case LIKELIHOOD:
87+
case WEIGHTED: {
88+
boolean isWeighted = (boolean)params.getOrDefault(KEY_IS_WEIGHTED, false);
89+
int claLearningPeriod = (int)params.getOrDefault(KEY_LEARNING_PERIOD, VALUE_NONE);
90+
int estimationSamples = (int)params.getOrDefault(KEY_ESTIMATION_SAMPLES, VALUE_NONE);
91+
92+
return new AnomalyLikelihood(useMovingAvg, windowSize, isWeighted, claLearningPeriod, estimationSamples);
93+
}
94+
default: return null;
95+
}
96+
}
97+
98+
/**
99+
* The raw anomaly score is the fraction of active columns not predicted.
100+
*
101+
* @param activeColumns an array of active column indices
102+
* @param prevPredictedColumns array of column indices predicted in the
103+
* previous step
104+
* @return anomaly score 0..1
105+
*/
106+
public static double computeRawAnomalyScore(int[] activeColumns, int[] prevPredictedColumns) {
107+
double score = 0;
108+
109+
int nActiveColumns = activeColumns.length;
110+
if(nActiveColumns > 0) {
111+
// Test whether each element of a 1-D array is also present in a second
112+
// array. Sum to get the total # of columns that are active and were
113+
// predicted.
114+
score = ArrayUtils.in1d(activeColumns, prevPredictedColumns).length;
115+
// Get the percent of active columns that were NOT predicted, that is
116+
// our anomaly score.
117+
score = (nActiveColumns - score) / (double)nActiveColumns;
118+
}else if(prevPredictedColumns.length > 0) {
119+
score = 1.0d;
120+
}
121+
122+
return score;
123+
}
124+
125+
/**
126+
* Compute the anomaly score as the percent of active columns not predicted.
127+
*
128+
* @param activeColumns array of active column indices
129+
* @param predictedColumns array of columns indices predicted in this step
130+
* (used for anomaly in step T+1)
131+
* @param inputValue (optional) value of current input to encoders
132+
* (eg "cat" for category encoder)
133+
* (used in anomaly-likelihood)
134+
* @param timestamp timestamp: (optional) date timestamp when the sample occurred
135+
* (used in anomaly-likelihood)
136+
* @return
137+
*/
138+
public abstract double compute(int[] activeColumns, int[] predictedColumns, Object inputValue, long timestamp);
139+
140+
}

0 commit comments

Comments
 (0)