Public
Edited
May 25, 2024
Importers
Insert cell
Insert cell
Insert cell
function loess_best(data){
//console.log("loess_best has been passed data:")
//console.log(data);
const localData = data.filter(d => isFinite(d[0]) && isFinite(d[1]))
//console.log(localData);
const grid = loess_grid(localData)
.sort(function(x,y){return d3.ascending(x.gcv,y.gcv);})
console.log("loess_best has grid:")
console.log(grid);
const bw = grid.length > 0 ? grid[0].bw : 0.5;
console.log("bandwidth selected: " + bw);
// fit loess with this bandwidth
const f = d3.regressionLoess()
.x(d => d[0])
.y(d => d[1])
.bandwidth(bw)
(localData);
//console.log(f);
return f;
}
Insert cell
function loess_resid(data,f){
const y_vec = data.map(d=>d[1])
const yhat = f.map(d=>d[1])
const n = data.length
var e = new Array(n)
for(let i = 0; i < n; i++){
e[i] = y_vec[i] - yhat[i];
}
return e;
}
Insert cell
function loess_trace(loess_data,bandwidth){

console.log("loess_trace has bandwidth " + bandwidth);
//console.log("loess trace has data:"); console.log(loess_data);
//const loess_data = data.slice().sort(function(x,y){return d3.ascending(x[0],y[0]);})

const x_vec = loess_data.map(d => d[0]);
//console.log("loess_trace x");
//console.log(x_vec);
const n = x_vec.length
const M = 50;

const nindx = n > M ? M : n;
var index = new Array(nindx);
if(nindx == M){
for(let i = 0; i < nindx; i++){
index[i] = Math.floor(i/nindx * n);
}
} else {
for(let i = 0; i < nindx; i++){
index[i] = i;
}
}
var trace = 0;
var tmpData = [];
var f;
for(let i=0; i<n; i++){
tmpData.push([x_vec[i], 0]);
}
// step through indices
for(let i=0; i<nindx; i++){
tmpData[index[i]][1] = 1.0;

f = d3.regressionLoess()
.x(d=>d[0])
.y(d=>d[1])
.bandwidth(bandwidth)
(tmpData);
trace += f.map(d => d[1])[i];
tmpData[index[i]][1] = 0.0;
}
console.log("loess_trace: trace = " + trace);
return trace;
}
Insert cell
function loess_gcv(data,bw){
console.log("loess_gcv has bandwidth " + bw);

const f = d3.regressionLoess()
.x(d=>d[0])
.y(d=>d[1])
.bandwidth(bw)(data);
const e = loess_resid(data,f);
//console.log("loess_gcv has residuals");
//console.log(e);
const v = loess_trace(data,bw);
console.log("loess_gcv: trace of smoother matrix " + v);
const n = e.length;
var n_ok = 0;
var e_ok = []
//console.log("loess_gcv has s = " + s);
for(let i=0; i<n; i++){
if(isNaN(e[i]) || !isFinite(e[i])){
//console.log("loess_gcv bad data: observation " + i + " residual = " + e[i]);
} else {
n_ok++;
e_ok.push(e[i]);
}
//if(i%100 == 0){
// console.log("loess_gcv: e[i] = " + e[i] + "gcv = " + gcv);
//}
}
var gcv = 0;
for(let i = 0; i<n_ok; i++){
gcv += (1/n_ok) * Math.pow(e_ok[i]/(1-(v/n_ok)),2);
}
console.log("loess_gcv: n_ok " + n_ok);
console.log("loess_gcv: gcv " + gcv);
return gcv;
}
Insert cell
function loess_grid(data){
const loess_data = data.slice().sort(function(x,y){return d3.ascending(x[0],y[0]);})
//console.log("loess_grid has been passed data:");
//console.log(data);
const bw = d3.range(.2,1,.05);
//console.log("loess_grid: bandwidths to assess");
//console.log(bw);
var out = new Array(bw.length);
for(let i=0; i<bw.length; i++){
//console.log("loess_grid: assessing with bandwidth " + bw[i]);
out[i] = {
bw: bw[i],
//sse: loess_sse(data,bw[i],xDim,yDim),
//trace: loess_trace(data,x,y,bw[i]),
gcv: loess_gcv(loess_data,bw[i]),
//cvss: loess_cvss(loess_data,bw[i])
}
}
//console.log("loess_grid will return")
//console.log(out);
return out.filter(d => !isNaN(d.gcv));
}
Insert cell
Insert cell
d3 = require("d3@7", "d3-regression@1")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more