kernelDensityEstimation function
Computes kernel density estimation for a set of data points.
data is the input data.
bandwidth is the kernel bandwidth (smoothing parameter).
If not provided, Silverman's rule of thumb is used.
kernel is the type of kernel to use (default: gaussian).
nPoints is the number of points to evaluate the density at.
range is the optional range min, max for evaluation.
Implementation
KernelDensityResult kernelDensityEstimation(
List<double> data, {
double? bandwidth,
KernelType kernel = KernelType.gaussian,
int nPoints = 100,
List<double>? range,
}) {
if (data.isEmpty) {
return KernelDensityResult(x: [], density: []);
}
// Calculate bandwidth using Silverman's rule if not provided
final h = bandwidth ?? _silvermanBandwidth(data);
// Determine evaluation range
double minX, maxX;
if (range != null && range.length >= 2) {
minX = range[0];
maxX = range[1];
} else {
minX = data.reduce(math.min) - 3 * h;
maxX = data.reduce(math.max) + 3 * h;
}
// Generate evaluation points
final xValues = List<double>.generate(
nPoints,
(i) => minX + (maxX - minX) * i / (nPoints - 1),
);
// Select kernel function
double Function(double) kernelFn;
switch (kernel) {
case KernelType.gaussian:
kernelFn = _gaussianKernel;
break;
case KernelType.epanechnikov:
kernelFn = _epanechnikovKernel;
break;
case KernelType.triangular:
kernelFn = _triangularKernel;
break;
case KernelType.uniform:
kernelFn = _uniformKernel;
break;
}
// Estimate density at each point
final n = data.length;
final density = List<double>.filled(nPoints, 0);
for (int i = 0; i < nPoints; i++) {
double sum = 0;
for (int j = 0; j < n; j++) {
sum += kernelFn((xValues[i] - data[j]) / h);
}
density[i] = sum / (n * h);
}
return KernelDensityResult(x: xValues, density: density);
}