UNPKG

@ai-on-browser/data-analysis-models

Version:

Data analysis model package without any dependencies

75 lines (68 loc) 1.92 kB
/** * Local Outlier Probability */ export default class LoOP { // https://github.com/vc1492a/PyNomaly // https://www.dbs.ifi.lmu.de/Publikationen/Papers/LoOP1649.pdf /** * @param {number} k Number of neighborhoods */ constructor(k) { this._k = k this._lambda = 1 } _distance(a, b) { return Math.sqrt(a.reduce((s, v, i) => s + (v - b[i]) ** 2, 0)) } _erf(z) { const p = 0.3275911 const a1 = 0.254829592 const a2 = -0.284496736 const a3 = 1.421413741 const a4 = -1.453152027 const a5 = 1.061405429 const sign = z < 0 ? -1 : 1 const t = 1 / (1 + p * Math.abs(z)) const erf = 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-z * z) return sign * erf } /** * Returns anomaly degrees. * @param {Array<Array<number>>} datas Training data * @returns {number[]} Predicted values */ predict(datas) { const n = datas.length const distances = [] for (let i = 0; i < n; i++) { distances[i] = [] distances[i][i] = 0 for (let j = 0; j < i; j++) { const d = this._distance(datas[i], datas[j]) distances[i][j] = distances[j][i] = d } } const pdist = [] const nears = [] for (let i = 0; i < n; i++) { const sdist = distances[i].map((v, k) => [v, k]) sdist.sort((a, b) => a[0] - b[0]) const nrest = sdist.slice(1, this._k + 1).map(v => v[1]) nears[i] = nrest.concat() const sd = nears[i].reduce((s, v) => s + distances[i][v] ** 2, 0) pdist[i] = this._lambda * Math.sqrt(sd / nears[i].length) } const plof = [] for (let i = 0; i < n; i++) { const epdist = nears[i].reduce((s, v) => s + pdist[v], 0) / nears[i].length plof[i] = pdist[i] / epdist - 1 } const nplof = this._lambda + Math.sqrt(plof.reduce((s, v) => s + v ** 2, 0) / n) const nplof2 = nplof * Math.sqrt(2) const loop = [] for (let i = 0; i < n; i++) { loop[i] = Math.max(0, this._erf(plof[i] / nplof2)) } return loop } }