/* version 3
Again slightly more useful & accurate than version 2 in that this version will try a little harder for when the supplied time is between the min & max.
I noticed in version 2 that f(1993.5) returned < than f(1993). Odd. This version, when supplied 1993.5, will grab values for the closest surrounding dataset values (1993 & 1994) and interpolate linearly between those two specifically.
*/
/* version 3 notes (on getting the between the indices)
4.5 // input time to predict
4, 7 // range times
100, 150 // range values
7-4 = 3 // time diff
150 - 100 = 50 // value diff
50/3 = 16.6xxxx // per value value
100 + ((4.5 - 4) * 16.6xxxx)
minV + ((input - minT) * perYear)
*/
var data = [{year:1992,cost:1440},
{year:1993,cost:1560},
{year:1994,cost:1620},
{year:1995,cost:1780},
{year:1996,cost:1860},
{year:1997,cost:1920},
{year:1998,cost:1940},
{year:1999,cost:1999},
{year:2000,cost:2040}];
var data2 = [];
for(var xint = 0;xint < 10;xint++)
data2.push({year:2000+xint,pay:10+(xint/10)});
// then do one for #pets compared to #renkou ppl in household
// data is the cost of a used car with x miles on it in a certain year; goal: given a year, predict the cost that year
// data2 is hourly pay each year starting 2000 $10.00/hr. Goal: given a year, predict the pay that year
// assumes array is sorted least to greatest
function getNearIdxs(ary, val){ // returns object with 2 valid indices (assuming ary was not empty)
if(ary.length < 2) return {min:0,max:0};
var out = {min:0,max:0};
for(var xint = 0,len=ary.length;xint < len;xint++){
if(val < ary[xint]){
out.max = xint;
out.min = Math.max(0,xint-1);
return out;
}
}
return out;
}
// where timeName is the variable per object with the time value (the consistent change over time)
// and valueName is the value we're trying to find given a time
// .predict(v): returns a predicted linear output
// Note: 2 same .times[] values (like year 1993, 1993, 1994) would confuse it and produce probably undesirable output
function reader(data, timeName, valueName){
this.times = [];
this.values = [];
this.minT = 1; // minimum time
this.maxT = 1;
this.minV = 1; // minimum value
this.maxV = 1;
this.diffT = 1;
this.diffV = 1;
this.perYear = 1; // final linear quotient
// sort the data so we can easily grab the closest values by indices (least to greatest)
data.sort((a,b,tname)=>{return a[tname]>b[tname];});
this.d = data;
// now let's try to make a mini model
this.minT = data[0][timeName];
this.maxT = data[0][timeName];
this.minV = data[0][valueName];
this.maxV = data[0][valueName];
for(var xint = 0;xint < data.length;xint++){
this.minT = Math.min(this.minT, data[xint][timeName]);
this.maxT = Math.max(this.maxT, data[xint][timeName]);
this.minV = Math.min(this.minV, data[xint][valueName]);
this.maxV = Math.max(this.maxV, data[xint][valueName]);
this.times.push(data[xint][timeName]);
this.values.push(data[xint][valueName]);
}
this.diffT = Math.max(1,this.maxT - this.minT);
this.diffV = Math.max(1,this.maxV - this.minV);
this.perYear = this.diffV / this.diffT; // cost per year linear avg
this.predict = function(time){
if(time > this.maxT){
return this.maxV + ((time-this.maxT) * this.perYear);
}else if(time < this.minT){
return this.minV - ((this.minT-time) * this.perYear);
}else{ // within range
var found = false;
var val = 0;
for(var xint = 0;xint < this.times.length;xint++){
if(this.times[xint] == time){
found = true;
val = this.values[xint];
break;
}
}
if(found){
return val; // found in defined dataset
}else{
// estimate
var x = getNearIdxs(this.times, time);
var diffT = this.times[x.max] - this.times[x.min];
var diffV = this.values[x.max] - this.values[x.min];
if(diffT == 0) diffT = 1;
var vPerT = diffV / diffT;
return this.values[x.min] + ((time - this.times[x.min]) * vPerT);
}
}
}
}
var r1 = new reader(data, 'year', 'cost');
console.log(r1.predict(1992));
console.log(r1.predict(1993));
console.log(r1.predict(1994));
console.log(r1.predict(1993.5));
console.log(r1.predict(1993.1));
console.log(r1.predict(1993.9));
var r2 = new reader(data2, 'year', 'pay');
console.log(r2.predict(2001));