Published
Edited
Aug 28, 2019
49 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
sampleRate = 1 / 30
Insert cell
detector = new OutlierDetector(variance_tHalf, mean_tHalf, cutoff, filterOutliers)
Insert cell
stats = {
detector.reset()
return samples.map(detector.assimilate);
}
Insert cell
function OutlierDetector (varianceDecayTime, meanDecayTime, outlierCutoff, filterOutliers) {
var mean = null
var tPrev = null
var n = 0;
var count = 0
var M2n = 0
var M20 = 1e-5
this.assimilate = sample => {
var result = {};
result.t = sample.t;
var dt = sample.t - tPrev;
var deviationsFromMean = Math.abs(sample.y - mean) / Math.sqrt(M2n / n);
var varianceDecayFactor = count < 2 ? 1 : Math.exp(-dt / varianceDecayTime * Math.log(2.0));

count++;
n = n * varianceDecayFactor + 1;
switch(count) {
case 1:
mean = sample.y;
M2n = M20;

result.mean = mean;
result.deviationsFromMean = 0.0;
result.isOutlier = false;

break;

case 2:
mean = (mean + sample.y) * 0.5;
M2n = Math.pow((mean - sample.y) * 10.0, 2)

result.mean = mean
result.deviationsFromMean = 0.0;
result.isOutlier = false;
break;

default:
var meanDecayFactor = Math.exp(-dt / meanDecayTime * Math.log(2.0));

if (!filterOutliers || (M2n === 0.0 || deviationsFromMean <= outlierCutoff)) {
var prevMean = mean;
mean = mean * meanDecayFactor + sample.y * (1.0 - meanDecayFactor);
M2n = M2n * varianceDecayFactor + (sample.y - prevMean) * (sample.y - mean);
}

result.mean = mean;
result.isOutlier = true;

}
result.y = sample.y
result.variance = M2n / n;
result.deviationsFromMean = Math.abs(result.y - result.mean) / Math.sqrt(result.variance)
result.outlierScore = result.deviationsFromMean / outlierCutoff
tPrev = sample.t;
return result;
}
this.reset = () => {
tPrev = null
mean = null
count = 0
M2n = M20
return this
}
}
Insert cell
samples = {
if (useRealData) {
return realData.map((d, i) => ({t: i * sampleRate, y: d}))
} else {
var drift = Math.random() * 2.0 - 1
var varianceWaviness = 5 + 30 * Math.random()
return new Array(n).fill(0).map((d, i) => {
var t = sampleRate * i
var variance = 0.2 * (1.0 + 0.6 * Math.sin(i / n * varianceWaviness))
var bias = 0.1 * Math.sin(i / n * 7) + drift * i / n;
if (Math.random() < outlierPercentage / 100) return {t, y: bias + (Math.random() * 2 - 1)}
return {t, y: bias + variance * (Math.random() * 2 - 1) * (Math.random() * 2 - 1)}
})
}
}
Insert cell
Insert cell
function lerp (a, b, x) {
return a * (1 - x) + b * x;
}
Insert cell
margin = ({top: 20, right: 10, bottom: 30, left: 40})
Insert cell
height = Math.min(500, Math.max(350, width * 0.75))
Insert cell
d3 = require("d3@5")
Insert cell
import {slider, checkbox} from '@jashkenas/inputs'
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more