@visactor/vutils 1.0.26 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/cjs/common/ascending.js +1 -2
  2. package/cjs/common/deviation.js +2 -1
  3. package/cjs/common/getType.js +1 -2
  4. package/cjs/common/isFunction.js +2 -1
  5. package/cjs/common/isObject.js +1 -2
  6. package/cjs/common/isPrototype.js +1 -1
  7. package/cjs/common/isRegExp.js +1 -1
  8. package/cjs/common/isShallowEqual.js +1 -1
  9. package/cjs/common/isString.js +1 -1
  10. package/cjs/common/isType.js +1 -1
  11. package/cjs/common/kde.d.ts +4 -0
  12. package/cjs/common/kde.js +25 -14
  13. package/cjs/common/kde.js.map +1 -1
  14. package/cjs/data-structure/bounds.js +1 -1
  15. package/cjs/data-structure/hashTable.js +2 -1
  16. package/cjs/data-structure/index.js +1 -1
  17. package/cjs/data-structure/matrix.js +1 -1
  18. package/cjs/data-structure/point.js +1 -1
  19. package/dist/index.js +65 -38
  20. package/dist/index.min.js +15 -15
  21. package/es/common/ascending.js +1 -2
  22. package/es/common/deviation.js +2 -1
  23. package/es/common/getType.js +1 -2
  24. package/es/common/isFunction.js +2 -1
  25. package/es/common/isObject.js +1 -2
  26. package/es/common/isPrototype.js +1 -1
  27. package/es/common/isRegExp.js +1 -1
  28. package/es/common/isShallowEqual.js +1 -1
  29. package/es/common/isString.js +1 -1
  30. package/es/common/isType.js +1 -1
  31. package/es/common/kde.d.ts +4 -0
  32. package/es/common/kde.js +29 -14
  33. package/es/common/kde.js.map +1 -1
  34. package/es/data-structure/bounds.js +1 -1
  35. package/es/data-structure/hashTable.js +2 -1
  36. package/es/data-structure/index.js +1 -1
  37. package/es/data-structure/matrix.js +1 -1
  38. package/es/data-structure/point.js +1 -1
  39. package/package.json +4 -5
  40. package/REGRESSION.md +0 -36
@@ -6,5 +6,4 @@ function ascending(a, b) {
6
6
 
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: !0
9
- }), exports.ascending = void 0, exports.ascending = ascending;
10
- //# sourceMappingURL=ascending.js.map
9
+ }), exports.ascending = void 0, exports.ascending = ascending;
@@ -11,4 +11,5 @@ function deviation(values, valueof) {
11
11
  return v ? Math.sqrt(v) : v;
12
12
  }
13
13
 
14
- exports.deviation = deviation;
14
+ exports.deviation = deviation;
15
+ //# sourceMappingURL=deviation.js.map
@@ -6,5 +6,4 @@ Object.defineProperty(exports, "__esModule", {
6
6
 
7
7
  const getType = value => ({}.toString.call(value).replace(/^\[object /, "").replace(/]$/, ""));
8
8
 
9
- exports.default = getType;
10
- //# sourceMappingURL=getType.js.map
9
+ exports.default = getType;
@@ -32,4 +32,5 @@ Object.defineProperty(exports, "__esModule", {
32
32
  // eslint-disable-next-line @typescript-eslint/ban-types
33
33
  const isFunction = value => "function" == typeof value;
34
34
 
35
- exports.default = isFunction;
35
+ exports.default = isFunction;
36
+ //# sourceMappingURL=isFunction.js.map
@@ -31,5 +31,4 @@ const isObject = value => {
31
31
  return null !== value && "object" === type || "function" === type;
32
32
  };
33
33
 
34
- exports.default = isObject;
35
- //# sourceMappingURL=isObject.js.map
34
+ exports.default = isObject;
@@ -10,4 +10,4 @@ const objectProto = Object.prototype, isPrototype = function(value) {
10
10
  };
11
11
 
12
12
  exports.default = isPrototype;
13
- //# sourceMappingURL=isPrototype.js.map
13
+ //# sourceMappingURL=isPrototype.js.map
@@ -13,4 +13,4 @@ Object.defineProperty(exports, "__esModule", {
13
13
  const isType_1 = __importDefault(require("./isType")), isRegExp = value => (0, isType_1.default)(value, "RegExp");
14
14
 
15
15
  exports.default = isRegExp;
16
- //# sourceMappingURL=isRegExp.js.map
16
+ //# sourceMappingURL=isRegExp.js.map
@@ -32,4 +32,4 @@ function isShallowEqual(objA, objB) {
32
32
  }
33
33
 
34
34
  exports.isShallowEqual = isShallowEqual;
35
- //# sourceMappingURL=isShallowEqual.js.map
35
+ //# sourceMappingURL=isShallowEqual.js.map
@@ -28,4 +28,4 @@ const isType_1 = __importDefault(require("./isType")), isString = (value, fuzzy
28
28
  * isString(1)
29
29
  * // => false
30
30
  */ exports.default = isString;
31
- //# sourceMappingURL=isString.js.map
31
+ //# sourceMappingURL=isString.js.map
@@ -13,4 +13,4 @@ Object.defineProperty(exports, "__esModule", {
13
13
  const isType = (value, type) => Object.prototype.toString.call(value) === `[object ${type}]`;
14
14
 
15
15
  exports.default = isType;
16
- //# sourceMappingURL=isType.js.map
16
+ //# sourceMappingURL=isType.js.map
@@ -22,6 +22,10 @@ export interface KDEOptions {
22
22
  kernel?: Kernel;
23
23
  bandwidth?: number;
24
24
  bandwidthMethod?: 'scott' | 'silverman';
25
+ /** Automatic bandwidth uses population deviation by default, preserving existing behavior. */
26
+ standardDeviation?: 'sample' | 'population';
27
+ /** Positive multiplier applied once to either fixed or automatic bandwidth. */
28
+ bandwidthAdjust?: number;
25
29
  }
26
30
  export interface KDEEvaluator {
27
31
  bandwidth: number;
package/cjs/common/kde.js CHANGED
@@ -11,8 +11,7 @@
11
11
  value: !0
12
12
  }), exports.kde = exports.silverman = exports.scott = exports.epanechnikov = exports.gaussian = void 0;
13
13
 
14
- /** Gaussian kernel (standard normal) */
15
- const gaussian = u => 1 / Math.sqrt(2 * Math.PI) * Math.exp(-.5 * u * u);
14
+ const mean_1 = require("./mean"), variance_1 = require("./variance"), gaussian = u => 1 / Math.sqrt(2 * Math.PI) * Math.exp(-.5 * u * u);
16
15
 
17
16
  exports.gaussian = gaussian;
18
17
 
@@ -36,32 +35,44 @@ function silverman(n, std, dim = 1) {
36
35
  /**
37
36
  * Compute standard deviation for numeric array
38
37
  */
39
- function std(values) {
38
+ function std(values, convention) {
40
39
  const n = values.length;
41
- if (0 === n) return 0;
42
- let mean = 0;
43
- for (let i = 0; i < n; i++) mean += values[i];
44
- mean /= n;
45
- let s = 0;
40
+ if (n < 2) return 0;
41
+ const center = (0, mean_1.mean)(values), differences = [];
42
+ let scale = 0, sourceScale = 1;
46
43
  for (let i = 0; i < n; i++) {
47
- const d = values[i] - mean;
48
- s += d * d;
44
+ const difference = values[i] - center;
45
+ differences.push(difference), scale = Math.max(scale, Math.abs(difference));
49
46
  }
50
- return Math.sqrt(s / n);
47
+ // Finite values of opposite signs can overflow subtraction although population deviation is representable.
48
+ if (scale === 1 / 0) {
49
+ sourceScale = Math.abs(center);
50
+ for (const value of values) sourceScale = Math.max(sourceScale, Math.abs(value));
51
+ scale = 0;
52
+ for (let i = 0; i < n; i++) differences[i] = values[i] / sourceScale - center / sourceScale,
53
+ scale = Math.max(scale, Math.abs(differences[i]));
54
+ }
55
+ if (0 === scale) return 0;
56
+ for (let i = 0; i < n; i++) differences[i] /= scale;
57
+ const correction = "population" === convention ? (n - 1) / n : 1;
58
+ return Math.sqrt((0, variance_1.variance)(differences) * correction) * scale * sourceScale;
51
59
  }
52
60
 
53
61
  /**
54
62
  * Factory: create a KDE evaluator for given data and options.
55
63
  * Usage: const model = kde(data, options); model.evaluate(x) or model.evaluate([x1,x2])
56
64
  */ function kde(data, options = {}) {
65
+ const deviation = void 0 === options.standardDeviation ? "population" : options.standardDeviation, adjustment = void 0 === options.bandwidthAdjust ? 1 : options.bandwidthAdjust;
66
+ if ("sample" !== deviation && "population" !== deviation) throw new RangeError("standardDeviation must be sample or population");
67
+ if (!Number.isFinite(adjustment) || adjustment <= 0) throw new RangeError("bandwidthAdjust must be finite and positive");
57
68
  const n = data.length, kernel = options.kernel || exports.gaussian;
58
69
  let h = options.bandwidth;
59
70
  if (!h || h <= 0) {
60
- const sd = std(data) || 0, method = options.bandwidthMethod || "scott";
71
+ const sd = std(data, deviation) || 0, method = options.bandwidthMethod || "scott";
61
72
  h = "silverman" === method ? silverman(n, sd, 1) : scott(n, sd, 1);
62
73
  }
63
74
  // if still zero (constant data), evaluator returns zeros
64
- if (!h || h <= 0) {
75
+ if (h *= adjustment, !h || h <= 0) {
65
76
  return {
66
77
  bandwidth: 0,
67
78
  kernel: kernel,
@@ -97,7 +108,7 @@ function std(values) {
97
108
  }
98
109
  };
99
110
  }
100
- const invNh = 1 / (n * h);
111
+ const invNh = 1 / n / h;
101
112
  function evalPoint(x) {
102
113
  let sum = 0;
103
114
  for (let j = 0; j < n; j++) sum += kernel((x - data[j]) / h);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/common/kde.ts"],"names":[],"mappings":"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","file":"kde.js","sourcesContent":["/**\n * Kernel Density Estimation (KDE) utilities\n *\n * Exports:\n * - Kernel functions: gaussian, epanechnikov\n * - bandwidth selectors: scott, silverman\n * - kde: main function to compute density estimates at provided points\n */\n\nexport type Kernel = (u: number) => number;\n\n/** Gaussian kernel (standard normal) */\nexport const gaussian: Kernel = (u: number) => {\n const invSqrt2Pi = 1 / Math.sqrt(2 * Math.PI);\n return invSqrt2Pi * Math.exp(-0.5 * u * u);\n};\n\n/** Epanechnikov kernel (compact support) */\nexport const epanechnikov: Kernel = (u: number) => {\n const absu = Math.abs(u);\n return absu <= 1 ? 0.75 * (1 - u * u) : 0;\n};\n\n/**\n * Bandwidth selectors\n * - scott: h = n^{-1/(d+4)} * std\n * - silverman: h = ( (4/(d+2))^{1/(d+4)} ) * n^{-1/(d+4)} * std\n */\nexport function scott(n: number, std: number, dim = 1) {\n if (n <= 0 || std === 0) {\n return 0;\n }\n return std * Math.pow(n, -1 / (dim + 4));\n}\n\nexport function silverman(n: number, std: number, dim = 1) {\n if (n <= 0 || std === 0) {\n return 0;\n }\n const factor = Math.pow(4 / (dim + 2), 1 / (dim + 4));\n return factor * std * Math.pow(n, -1 / (dim + 4));\n}\n\nexport interface KDEOptions {\n kernel?: Kernel;\n bandwidth?: number; // fixed bandwidth\n bandwidthMethod?: 'scott' | 'silverman';\n // if bandwidth not provided, compute from data using method\n}\n\n/**\n * Compute standard deviation for numeric array\n */\nfunction std(values: number[]) {\n const n = values.length;\n if (n === 0) {\n return 0;\n }\n let mean = 0;\n for (let i = 0; i < n; i++) {\n mean += values[i];\n }\n mean /= n;\n let s = 0;\n for (let i = 0; i < n; i++) {\n const d = values[i] - mean;\n s += d * d;\n }\n return Math.sqrt(s / n);\n}\n\nexport interface KDEEvaluator {\n bandwidth: number;\n kernel: Kernel;\n /**\n * Evaluate density at a single point or array of points.\n * - If given a number, returns a number.\n * - If given an array, returns an array aligned with input.\n */\n evaluate: ((x: number) => number) & ((xs: number[]) => number[]);\n /**\n * Produce N uniformly spaced points across the data range and evaluate densities.\n * Returns an array { x: number, y: number }[].\n */\n evaluateGrid: (N: number) => { x: number; y: number }[];\n}\n\n/**\n * Factory: create a KDE evaluator for given data and options.\n * Usage: const model = kde(data, options); model.evaluate(x) or model.evaluate([x1,x2])\n */\nexport function kde(data: number[], options: KDEOptions = {}): KDEEvaluator {\n const n = data.length;\n const kernel = options.kernel || gaussian;\n\n let h = options.bandwidth;\n if (!h || h <= 0) {\n const sd = std(data) || 0;\n const method = options.bandwidthMethod || 'scott';\n if (method === 'silverman') {\n h = silverman(n, sd, 1);\n } else {\n h = scott(n, sd, 1);\n }\n }\n\n // if still zero (constant data), evaluator returns zeros\n if (!h || h <= 0) {\n const zerosEval = (x: number | number[]) => {\n if (Array.isArray(x)) {\n const out: number[] = [];\n for (let i = 0; i < x.length; i++) {\n out.push(0);\n }\n return out;\n }\n return 0;\n };\n const zerosGrid = (N: number) => {\n const out: { x: number; y: number }[] = [];\n if (N <= 0) {\n return out;\n }\n // compute data min (use data range if available)\n let min = Infinity;\n let max = -Infinity;\n for (let j = 0; j < n; j++) {\n const v = data[j];\n if (v < min) {\n min = v;\n }\n if (v > max) {\n max = v;\n }\n }\n if (min === Infinity || max === -Infinity) {\n for (let i = 0; i < N; i++) {\n out.push({ x: 0, y: 0 });\n }\n return out;\n }\n for (let i = 0; i < N; i++) {\n out.push({ x: min, y: 0 });\n }\n return out;\n };\n return {\n bandwidth: 0,\n kernel,\n evaluate: zerosEval as any,\n evaluateGrid: zerosGrid\n };\n }\n\n const invNh = 1 / (n * h);\n\n function evalPoint(x: number) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n sum += kernel((x - data[j]) / h);\n }\n return sum * invNh;\n }\n\n function evaluate(x: number | number[]) {\n if (Array.isArray(x)) {\n const out: number[] = [];\n for (let i = 0; i < x.length; i++) {\n out.push(evalPoint(x[i]));\n }\n return out;\n }\n return evalPoint(x as number);\n }\n\n return {\n bandwidth: h,\n kernel,\n evaluate: evaluate as any,\n evaluateGrid(N: number) {\n const out: { x: number; y: number }[] = [];\n if (N <= 0) {\n return out;\n }\n // compute data range\n let min = Infinity;\n let max = -Infinity;\n for (let i = 0; i < n; i++) {\n const v = data[i];\n if (v < min) {\n min = v;\n }\n if (v > max) {\n max = v;\n }\n }\n if (min === Infinity || max === -Infinity) {\n return out;\n }\n if (min === max) {\n // single point repeated\n for (let i = 0; i < N; i++) {\n out.push({ x: min, y: evalPoint(min) });\n }\n return out;\n }\n\n const step = (max - min) / (N - 1);\n for (let i = 0; i < N; i++) {\n const x = i === N - 1 ? max : min + step * i;\n out.push({ x, y: evalPoint(x) });\n }\n return out;\n }\n };\n}\n\nexport default kde;\n"]}
1
+ {"version":3,"sources":["../src/common/kde.ts"],"names":[],"mappings":"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","file":"kde.js","sourcesContent":["/**\n * Kernel Density Estimation (KDE) utilities\n *\n * Exports:\n * - Kernel functions: gaussian, epanechnikov\n * - bandwidth selectors: scott, silverman\n * - kde: main function to compute density estimates at provided points\n */\n\nimport { mean } from './mean';\nimport { variance } from './variance';\n\nexport type Kernel = (u: number) => number;\n\n/** Gaussian kernel (standard normal) */\nexport const gaussian: Kernel = (u: number) => {\n const invSqrt2Pi = 1 / Math.sqrt(2 * Math.PI);\n return invSqrt2Pi * Math.exp(-0.5 * u * u);\n};\n\n/** Epanechnikov kernel (compact support) */\nexport const epanechnikov: Kernel = (u: number) => {\n const absu = Math.abs(u);\n return absu <= 1 ? 0.75 * (1 - u * u) : 0;\n};\n\n/**\n * Bandwidth selectors\n * - scott: h = n^{-1/(d+4)} * std\n * - silverman: h = ( (4/(d+2))^{1/(d+4)} ) * n^{-1/(d+4)} * std\n */\nexport function scott(n: number, std: number, dim = 1) {\n if (n <= 0 || std === 0) {\n return 0;\n }\n return std * Math.pow(n, -1 / (dim + 4));\n}\n\nexport function silverman(n: number, std: number, dim = 1) {\n if (n <= 0 || std === 0) {\n return 0;\n }\n const factor = Math.pow(4 / (dim + 2), 1 / (dim + 4));\n return factor * std * Math.pow(n, -1 / (dim + 4));\n}\n\nexport interface KDEOptions {\n kernel?: Kernel;\n bandwidth?: number; // fixed bandwidth\n bandwidthMethod?: 'scott' | 'silverman';\n /** Automatic bandwidth uses population deviation by default, preserving existing behavior. */\n standardDeviation?: 'sample' | 'population';\n /** Positive multiplier applied once to either fixed or automatic bandwidth. */\n bandwidthAdjust?: number;\n // if bandwidth not provided, compute from data using method\n}\n\n/**\n * Compute standard deviation for numeric array\n */\nfunction std(values: number[], convention: 'sample' | 'population') {\n const n = values.length;\n if (n < 2) {\n return 0;\n }\n const center = mean(values);\n const differences: number[] = [];\n let scale = 0;\n let sourceScale = 1;\n for (let i = 0; i < n; i++) {\n const difference = values[i] - center;\n differences.push(difference);\n scale = Math.max(scale, Math.abs(difference));\n }\n // Finite values of opposite signs can overflow subtraction although population deviation is representable.\n if (scale === Infinity) {\n sourceScale = Math.abs(center);\n for (const value of values) {\n sourceScale = Math.max(sourceScale, Math.abs(value));\n }\n scale = 0;\n for (let i = 0; i < n; i++) {\n differences[i] = values[i] / sourceScale - center / sourceScale;\n scale = Math.max(scale, Math.abs(differences[i]));\n }\n }\n if (scale === 0) {\n return 0;\n }\n for (let i = 0; i < n; i++) {\n differences[i] /= scale;\n }\n const correction = convention === 'population' ? (n - 1) / n : 1;\n return Math.sqrt(variance(differences) * correction) * scale * sourceScale;\n}\n\nexport interface KDEEvaluator {\n bandwidth: number;\n kernel: Kernel;\n /**\n * Evaluate density at a single point or array of points.\n * - If given a number, returns a number.\n * - If given an array, returns an array aligned with input.\n */\n evaluate: ((x: number) => number) & ((xs: number[]) => number[]);\n /**\n * Produce N uniformly spaced points across the data range and evaluate densities.\n * Returns an array { x: number, y: number }[].\n */\n evaluateGrid: (N: number) => { x: number; y: number }[];\n}\n\n/**\n * Factory: create a KDE evaluator for given data and options.\n * Usage: const model = kde(data, options); model.evaluate(x) or model.evaluate([x1,x2])\n */\nexport function kde(data: number[], options: KDEOptions = {}): KDEEvaluator {\n const deviation = options.standardDeviation === undefined ? 'population' : options.standardDeviation;\n const adjustment = options.bandwidthAdjust === undefined ? 1 : options.bandwidthAdjust;\n if (deviation !== 'sample' && deviation !== 'population') {\n throw new RangeError('standardDeviation must be sample or population');\n }\n if (!Number.isFinite(adjustment) || adjustment <= 0) {\n throw new RangeError('bandwidthAdjust must be finite and positive');\n }\n const n = data.length;\n const kernel = options.kernel || gaussian;\n\n let h = options.bandwidth;\n if (!h || h <= 0) {\n const sd = std(data, deviation) || 0;\n const method = options.bandwidthMethod || 'scott';\n if (method === 'silverman') {\n h = silverman(n, sd, 1);\n } else {\n h = scott(n, sd, 1);\n }\n }\n h *= adjustment;\n\n // if still zero (constant data), evaluator returns zeros\n if (!h || h <= 0) {\n const zerosEval = (x: number | number[]) => {\n if (Array.isArray(x)) {\n const out: number[] = [];\n for (let i = 0; i < x.length; i++) {\n out.push(0);\n }\n return out;\n }\n return 0;\n };\n const zerosGrid = (N: number) => {\n const out: { x: number; y: number }[] = [];\n if (N <= 0) {\n return out;\n }\n // compute data min (use data range if available)\n let min = Infinity;\n let max = -Infinity;\n for (let j = 0; j < n; j++) {\n const v = data[j];\n if (v < min) {\n min = v;\n }\n if (v > max) {\n max = v;\n }\n }\n if (min === Infinity || max === -Infinity) {\n for (let i = 0; i < N; i++) {\n out.push({ x: 0, y: 0 });\n }\n return out;\n }\n for (let i = 0; i < N; i++) {\n out.push({ x: min, y: 0 });\n }\n return out;\n };\n return {\n bandwidth: 0,\n kernel,\n evaluate: zerosEval as any,\n evaluateGrid: zerosGrid\n };\n }\n\n const invNh = 1 / n / h;\n\n function evalPoint(x: number) {\n let sum = 0;\n for (let j = 0; j < n; j++) {\n sum += kernel((x - data[j]) / h);\n }\n return sum * invNh;\n }\n\n function evaluate(x: number | number[]) {\n if (Array.isArray(x)) {\n const out: number[] = [];\n for (let i = 0; i < x.length; i++) {\n out.push(evalPoint(x[i]));\n }\n return out;\n }\n return evalPoint(x as number);\n }\n\n return {\n bandwidth: h,\n kernel,\n evaluate: evaluate as any,\n evaluateGrid(N: number) {\n const out: { x: number; y: number }[] = [];\n if (N <= 0) {\n return out;\n }\n // compute data range\n let min = Infinity;\n let max = -Infinity;\n for (let i = 0; i < n; i++) {\n const v = data[i];\n if (v < min) {\n min = v;\n }\n if (v > max) {\n max = v;\n }\n }\n if (min === Infinity || max === -Infinity) {\n return out;\n }\n if (min === max) {\n // single point repeated\n for (let i = 0; i < N; i++) {\n out.push({ x: min, y: evalPoint(min) });\n }\n return out;\n }\n\n const step = (max - min) / (N - 1);\n for (let i = 0; i < N; i++) {\n const x = i === N - 1 ? max : min + step * i;\n out.push({ x, y: evalPoint(x) });\n }\n return out;\n }\n };\n}\n\nexport default kde;\n"]}
@@ -236,4 +236,4 @@ class OBBBounds extends Bounds {
236
236
  }
237
237
 
238
238
  exports.OBBBounds = OBBBounds;
239
- //# sourceMappingURL=bounds.js.map
239
+ //# sourceMappingURL=bounds.js.map
@@ -120,4 +120,5 @@ class HashTable {
120
120
  }
121
121
  }
122
122
 
123
- exports.HashTable = HashTable;
123
+ exports.HashTable = HashTable;
124
+ //# sourceMappingURL=hashTable.js.map
@@ -23,4 +23,4 @@ __exportStar(require("./hashTable"), exports),
23
23
  // Point
24
24
  __exportStar(require("./point"), exports), __exportStar(require("./bounds"), exports),
25
25
  __exportStar(require("./matrix"), exports);
26
- //# sourceMappingURL=index.js.map
26
+ //# sourceMappingURL=index.js.map
@@ -158,4 +158,4 @@ function normalTransform(out, origin, x, y, scaleX, scaleY, angle, rotateCenter)
158
158
  }
159
159
 
160
160
  exports.Matrix = Matrix, exports.normalTransform = normalTransform;
161
- //# sourceMappingURL=matrix.js.map
161
+ //# sourceMappingURL=matrix.js.map
@@ -82,4 +82,4 @@ class PolarPoint {
82
82
  }
83
83
 
84
84
  exports.PolarPoint = PolarPoint;
85
- //# sourceMappingURL=point.js.map
85
+ //# sourceMappingURL=point.js.map
package/dist/index.js CHANGED
@@ -3145,6 +3145,33 @@
3145
3145
  };
3146
3146
  }
3147
3147
 
3148
+ /** 有限数值的均值;空输入没有均值,不修改输入。 */
3149
+ function mean(values) {
3150
+ if (!values.length) {
3151
+ return undefined;
3152
+ }
3153
+ let scale = 0;
3154
+ for (const value of values) {
3155
+ if (!Number.isFinite(value)) {
3156
+ throw new RangeError('mean requires finite numbers');
3157
+ }
3158
+ scale = Math.max(scale, Math.abs(value));
3159
+ }
3160
+ if (scale === 0) {
3161
+ return 0;
3162
+ }
3163
+ let sum = 0;
3164
+ let correction = 0;
3165
+ for (const value of values) {
3166
+ const next = value / scale;
3167
+ const total = sum + next;
3168
+ // Neumaier compensation retains small contributions even when larger values cancel.
3169
+ correction += Math.abs(sum) >= Math.abs(next) ? sum - total + next : next - total + sum;
3170
+ sum = total;
3171
+ }
3172
+ return ((sum + correction) / values.length) * scale;
3173
+ }
3174
+
3148
3175
  /**
3149
3176
  * Kernel Density Estimation (KDE) utilities
3150
3177
  *
@@ -3184,33 +3211,59 @@
3184
3211
  /**
3185
3212
  * Compute standard deviation for numeric array
3186
3213
  */
3187
- function std(values) {
3214
+ function std(values, convention) {
3188
3215
  const n = values.length;
3189
- if (n === 0) {
3216
+ if (n < 2) {
3190
3217
  return 0;
3191
3218
  }
3192
- let mean = 0;
3219
+ const center = mean(values);
3220
+ const differences = [];
3221
+ let scale = 0;
3222
+ let sourceScale = 1;
3193
3223
  for (let i = 0; i < n; i++) {
3194
- mean += values[i];
3224
+ const difference = values[i] - center;
3225
+ differences.push(difference);
3226
+ scale = Math.max(scale, Math.abs(difference));
3227
+ }
3228
+ // Finite values of opposite signs can overflow subtraction although population deviation is representable.
3229
+ if (scale === Infinity) {
3230
+ sourceScale = Math.abs(center);
3231
+ for (const value of values) {
3232
+ sourceScale = Math.max(sourceScale, Math.abs(value));
3233
+ }
3234
+ scale = 0;
3235
+ for (let i = 0; i < n; i++) {
3236
+ differences[i] = values[i] / sourceScale - center / sourceScale;
3237
+ scale = Math.max(scale, Math.abs(differences[i]));
3238
+ }
3239
+ }
3240
+ if (scale === 0) {
3241
+ return 0;
3195
3242
  }
3196
- mean /= n;
3197
- let s = 0;
3198
3243
  for (let i = 0; i < n; i++) {
3199
- const d = values[i] - mean;
3200
- s += d * d;
3244
+ differences[i] /= scale;
3201
3245
  }
3202
- return Math.sqrt(s / n);
3246
+ const correction = convention === 'population' ? (n - 1) / n : 1;
3247
+ return Math.sqrt(variance(differences) * correction) * scale * sourceScale;
3203
3248
  }
3204
3249
  /**
3205
3250
  * Factory: create a KDE evaluator for given data and options.
3206
3251
  * Usage: const model = kde(data, options); model.evaluate(x) or model.evaluate([x1,x2])
3207
3252
  */
3208
3253
  function kde(data, options = {}) {
3254
+ const deviation = options.standardDeviation === undefined ? 'population' : options.standardDeviation;
3255
+ const adjustment = options.bandwidthAdjust === undefined ? 1 : options.bandwidthAdjust;
3256
+ if (deviation !== 'sample' && deviation !== 'population') {
3257
+ throw new RangeError('standardDeviation must be sample or population');
3258
+ }
3259
+ if (!Number.isFinite(adjustment) || adjustment <= 0) {
3260
+ throw new RangeError('bandwidthAdjust must be finite and positive');
3261
+ }
3209
3262
  const n = data.length;
3210
3263
  const kernel = options.kernel || gaussian;
3211
3264
  let h = options.bandwidth;
3212
3265
  if (!h || h <= 0) {
3213
- const sd = std(data) || 0;
3266
+ const sd = std(data, deviation) || 0;
3214
3267
  const method = options.bandwidthMethod || 'scott';
3215
3268
  if (method === 'silverman') {
3216
3269
  h = silverman(n, sd, 1);
@@ -3219,6 +3272,7 @@
3219
3272
  h = scott(n, sd, 1);
3220
3273
  }
3221
3274
  }
3275
+ h *= adjustment;
3222
3276
  // if still zero (constant data), evaluator returns zeros
3223
3277
  if (!h || h <= 0) {
3224
3278
  const zerosEval = (x) => {
@@ -3266,7 +3320,7 @@
3266
3320
  evaluateGrid: zerosGrid
3267
3321
  };
3268
3322
  }
3269
- const invNh = 1 / (n * h);
3323
+ const invNh = 1 / n / h;
3270
3324
  function evalPoint(x) {
3271
3325
  let sum = 0;
3272
3326
  for (let j = 0; j < n; j++) {
@@ -3523,33 +3577,6 @@
3523
3577
  return method === 'kendall' ? kendall(x, y) : method === 'spearman' ? pearson(ranks(x), ranks(y)) : pearson(x, y);
3524
3578
  }
3525
3579
 
3526
- /** 有限数值的均值;空输入没有均值,不修改输入。 */
3527
- function mean(values) {
3528
- if (!values.length) {
3529
- return undefined;
3530
- }
3531
- let scale = 0;
3532
- for (const value of values) {
3533
- if (!Number.isFinite(value)) {
3534
- throw new RangeError('mean requires finite numbers');
3535
- }
3536
- scale = Math.max(scale, Math.abs(value));
3537
- }
3538
- if (scale === 0) {
3539
- return 0;
3540
- }
3541
- let sum = 0;
3542
- let correction = 0;
3543
- for (const value of values) {
3544
- const next = value / scale;
3545
- const total = sum + next;
3546
- // Neumaier compensation retains small contributions even when larger values cancel.
3547
- correction += Math.abs(sum) >= Math.abs(next) ? sum - total + next : next - total + sum;
3548
- sum = total;
3549
- }
3550
- return ((sum + correction) / values.length) * scale;
3551
- }
3552
-
3553
3580
  /** 有放回重采样;回调不得修改或持有复用的只读样本缓冲区。 */
3554
3581
  function bootstrapEstimate(values, estimator, options) {
3555
3582
  if (!values.length ||