@visactor/vmind
Version:
<div align="center"> <a href="https://github.com/VisActor#gh-light-mode-only" target="_blank"> <img alt="VisActor Logo" width="200" src="https://github.com/VisActor/.github/blob/main/profile/logo_500_200_light.svg"/> </a> <a href="https://githu
74 lines (67 loc) • 4.26 kB
JavaScript
;
var __importDefault = this && this.__importDefault || function(mod) {
return mod && mod.__esModule ? mod : {
default: mod
};
};
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.LOFOutlier = exports.LOF = void 0;
const euclidean_distance_1 = __importDefault(require("euclidean-distance")), vutils_1 = require("@visactor/vutils"), type_1 = require("../../type"), types_1 = require("../../../../types"), utils_1 = require("../../utils"), knn = (k, pIndex, distanceMap) => {
const distanceArr = distanceMap[pIndex];
return distanceMap.map(((data, index) => [ index, distanceArr[index] ])).filter((([index, distance]) => index !== pIndex)).sort((([index1, distance1], [index2, distance2]) => distance1 - distance2)).slice(0, k);
}, kd = (knnMap, pIndex) => {
const kNeighbors = knnMap[pIndex], [index, distance] = kNeighbors.reduce(((acc, dis) => acc[1] > dis[1] ? acc : dis));
return distance;
}, rd = (knnMap, distanceMap, pIndex, oIndex) => Math.max(kd(knnMap, oIndex), distanceMap[pIndex][oIndex]), sigmaRdCalc = (nearestArray, knnMap, distanceMap, pIndex) => nearestArray.map((([oIndex, distance]) => rd(knnMap, distanceMap, pIndex, oIndex))).reduce(((d1, d2) => d1 + d2)), lrd = (pIndex, knnMap, distanceMap) => {
const nearestArray = knnMap[pIndex], sigmaRd = sigmaRdCalc(nearestArray, knnMap, distanceMap, pIndex);
return sigmaRd - 0 <= Number.EPSILON ? 1 : nearestArray.length / sigmaRd;
}, onePointLOF = (dataIndex, knnMap, lrdArray) => {
const nearestArray = knnMap[dataIndex];
return nearestArray.map((([oIndex]) => lrdArray[oIndex] / lrdArray[dataIndex])).reduce(((d1, d2) => d1 + d2)) / nearestArray.length;
}, autoK = dataLength => dataLength > 10 ? 8 : dataLength > 4 ? 4 : 2, LOF = (dataList, threshold = 3, propsK) => {
const k = propsK || ((dataLength = dataList.length) > 10 ? 8 : dataLength > 4 ? 4 : 2);
var dataLength;
if (k >= dataList.length) return [];
const distanceMap = new Array(dataList.length).fill(0).map((d => []));
for (let i = 0; i < dataList.length; i++) for (let j = i + 1; j < dataList.length; j++) {
const distance = (0, euclidean_distance_1.default)([ dataList[i] ], [ dataList[j] ]);
distanceMap[i][j] = distance, distanceMap[j][i] = distance;
}
const knnMap = dataList.map(((v, index) => knn(k, index, distanceMap))), lrdArr = dataList.map(((v, index) => lrd(index, knnMap, distanceMap)));
return dataList.map(((v, index) => onePointLOF(index, knnMap, lrdArr))).map(((score, index) => score >= threshold ? {
index: index,
score: score
} : void 0)).filter(Boolean);
};
exports.LOF = LOF;
const lofAlgoFunc = (context, options) => {
const result = [], {k: k, threshold: threshold = 3} = options || {}, {seriesDataMap: seriesDataMap, cell: cell, spec: spec} = context, {y: celly} = cell, yField = (0,
vutils_1.isArray)(celly) ? celly.flat() : [ celly ];
return Object.keys(seriesDataMap).forEach((group => {
const dataset = seriesDataMap[group];
yField.forEach((field => {
if ((0, utils_1.isPercenSeries)(spec, field)) return;
const dataList = dataset.map((d => Number(d.dataItem[field])));
(0, exports.LOF)(dataList, threshold, k).forEach((insight => {
const {score: score, index: index} = insight, insightDataItem = dataset[index], lofInsight = {
type: type_1.InsightType.Outlier,
data: [ insightDataItem ],
fieldId: field,
value: insightDataItem.dataItem[field],
significant: score / threshold,
seriesName: group
};
result.push(lofInsight);
}));
}));
})), result;
};
exports.LOFOutlier = {
name: "lof",
forceChartType: [ types_1.ChartType.DualAxisChart, types_1.ChartType.LineChart, types_1.ChartType.BarChart, types_1.ChartType.AreaChart, types_1.ChartType.RadarChart, types_1.ChartType.PieChart, types_1.ChartType.RoseChart, types_1.ChartType.WaterFallChart ],
insightType: type_1.InsightType.Outlier,
algorithmFunction: lofAlgoFunc,
supportPercent: !1
};
//# sourceMappingURL=lof.js.map