-
Notifications
You must be signed in to change notification settings - Fork 224
/
kernel_density_estimation.js
90 lines (83 loc) · 3.03 KB
/
kernel_density_estimation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import interquartileRange from "./interquartile_range";
import stddev from "./sample_standard_deviation";
const SQRT_2PI = Math.sqrt(2 * Math.PI);
/**
* [Well-known kernels](https://en.wikipedia.org/wiki/Kernel_(statistics)#Kernel_functions_in_common_use)
* @private
*/
const kernels = {
/**
* The gaussian kernel.
* @private
*/
gaussian: function (u) {
return Math.exp(-0.5 * u * u) / SQRT_2PI;
}
};
/**
* Well known bandwidth selection methods
* @private
*/
const bandwidthMethods = {
/**
* The ["normal reference distribution"
* rule-of-thumb](https://stat.ethz.ch/R-manual/R-devel/library/MASS/html/bandwidth.nrd.html),
* a commonly used version of [Silverman's
* rule-of-thumb](https://en.wikipedia.org/wiki/Kernel_density_estimation#A_rule-of-thumb_bandwidth_estimator).
* @private
*/
nrd: function (x) {
let s = stddev(x);
const iqr = interquartileRange(x);
if (typeof iqr === "number") {
s = Math.min(s, iqr / 1.34);
}
return 1.06 * s * Math.pow(x.length, -0.2);
}
};
/**
* [Kernel density estimation](https://en.wikipedia.org/wiki/Kernel_density_estimation)
* is a useful tool for, among other things, estimating the shape of the
* underlying probability distribution from a sample.
*
* @name kernelDensityEstimation
* @param X sample values
* @param kernel The kernel function to use. If a function is provided, it should return non-negative values and integrate to 1. Defaults to 'gaussian'.
* @param bandwidthMethod The "bandwidth selection" method to use, or a fixed bandwidth value. Defaults to "nrd", the commonly-used ["normal reference distribution" rule-of-thumb](https://stat.ethz.ch/R-manual/R-devel/library/MASS/html/bandwidth.nrd.html).
* @returns {Function} An estimated [probability density function](https://en.wikipedia.org/wiki/Probability_density_function) for the given sample. The returned function runs in `O(X.length)`.
*/
function kernelDensityEstimation(X, kernel, bandwidthMethod) {
let kernelFn;
if (kernel === undefined) {
kernelFn = kernels.gaussian;
} else if (typeof kernel === "string") {
if (!kernels[kernel]) {
throw new Error('Unknown kernel "' + kernel + '"');
}
kernelFn = kernels[kernel];
} else {
kernelFn = kernel;
}
let bandwidth;
if (typeof bandwidthMethod === "undefined") {
bandwidth = bandwidthMethods.nrd(X);
} else if (typeof bandwidthMethod === "string") {
if (!bandwidthMethods[bandwidthMethod]) {
throw new Error(
'Unknown bandwidth method "' + bandwidthMethod + '"'
);
}
bandwidth = bandwidthMethods[bandwidthMethod](X);
} else {
bandwidth = bandwidthMethod;
}
return function (x) {
let i = 0;
let sum = 0;
for (i = 0; i < X.length; i++) {
sum += kernelFn((x - X[i]) / bandwidth);
}
return sum / bandwidth / X.length;
};
}
export default kernelDensityEstimation;