Created
January 13, 2022 21:20
-
-
Save dkatz23238/7803f12d61e99bb988c1b3315b0dda13 to your computer and use it in GitHub Desktop.
Timeseries.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* @param {DateRange} index | |
*/ | |
let invertIndex = (index) => { | |
let invIndex = {}; | |
for (let i = 0; i < index.values.length; i++) { | |
invIndex[index.values[i]] = i; | |
} | |
return invIndex; | |
}; | |
// a and b must have a shape and get method | |
let sumVectors = (a, b) => { | |
if (a.shape != b.shape) { | |
throw `Can't sum vector ${a.shape} with vector ${b.shape}`; | |
} | |
let results = []; | |
for (let i = 0; i < a.shape; i++) { | |
results.push(a.get(i) + b.get(i)); | |
} | |
return new Vector(results); | |
}; | |
let vectorScalarProduct = (s, v) => { | |
return v.getValues().map((i) => s * i); | |
}; | |
// v must hold an array with summable values | |
let averageVector = (v) => { | |
return v.values.reduce((i, j) => i + j, 0) / v.values.length; | |
}; | |
// Mixins | |
let summableMixin = (Base) => | |
class extends Base { | |
sum(vector) { | |
return sumVectors(this, vector); | |
} | |
}; | |
let meanableMixin = (Base) => | |
class extends Base { | |
mean() { | |
return averageVector(this); | |
} | |
}; | |
let pushableMixin = (Base) => | |
class extends Base { | |
push(v) { | |
this.values.push(v); | |
this.shape++; | |
} | |
}; | |
let valueablesMixin = (Base) => | |
class extends Base { | |
getValues() { | |
return this.values; | |
} | |
}; | |
let scalarProductableMixin = (Base) => | |
class extends Base { | |
prod(s) { | |
return new Vector(vectorScalarProduct(s, this)); | |
} | |
}; | |
let scalarSummableMixin = (Base) => | |
class extends Base { | |
scalarSum(s) { | |
return new Vector(s.getValues().map((i) => i + s)); | |
} | |
}; | |
class VectorBase { | |
constructor(array) { | |
this.values = array; | |
this.shape = array.length; | |
} | |
set(pos, val) { | |
// Positional set | |
this.values[pos] = val; | |
} | |
get(pos) { | |
// Positional get | |
return this.values[pos]; | |
} | |
} | |
// | |
// | |
class Vector extends scalarSummableMixin( | |
scalarProductableMixin( | |
// | |
valueablesMixin( | |
// | |
pushableMixin( | |
// | |
meanableMixin( | |
// | |
summableMixin( | |
// | |
VectorBase | |
) | |
) | |
) | |
) | |
) | |
) {} | |
class DateRange extends valueablesMixin( | |
// | |
pushableMixin( | |
// | |
VectorBase | |
) | |
) {} | |
class TimeSeries { | |
#index; | |
#vector; | |
#invIndex; | |
constructor(index, values) { | |
if (!(index instanceof DateRange) || !(values instanceof Vector)) { | |
throw "index must be DateRange and values must be Vector"; | |
} | |
this.#index = new DateRange(index.getValues()); | |
this.#vector = new Vector(values.getValues()); | |
this.#invIndex = invertIndex(this.#index); | |
} | |
values() { | |
return new Vector(this.#vector.getValues()); | |
} | |
index() { | |
return new DateRange(this.#index.getValues()); | |
} | |
invIndex() { | |
return invertIndex(this.#index); | |
} | |
setValueByPos(pos, value) { | |
this.#vector.set(pos, value); | |
} | |
setValueByIndex(date, value) { | |
let pos = this.#invIndex[date]; | |
if (pos === undefined) { | |
throw date + " Not in index"; | |
} | |
this.#vector.set(pos, value); | |
} | |
setIndexByPos(index, position) { | |
if (position == null) { | |
throw "position can't be null"; | |
} | |
this.#index.set(position, index); | |
this.#invIndex = invertIndex(this.#index); | |
} | |
push(date, value) { | |
this.#vector.push(value); | |
this.#index.push(date); | |
this.#invIndex = invertIndex(this.#index); | |
} | |
sum(ts) { | |
if (ts.index().getValues() !== this.#index.getValues()) { | |
throw "Indexes don't much"; | |
} | |
return new TimeSeries(this.index(), this.values().sum(ts.values())); | |
} | |
prod(s) { | |
return new TimeSeries(this.index(), this.values().prod(s)); | |
} | |
copy() { | |
return new TimeSeries(this.index(), this.values()); | |
} | |
records() { | |
let records = []; | |
for (let i = 0; i < this.#vector.shape; i++) { | |
records.push({ | |
date: this.#index.get(i), | |
value: this.#vector.get(i), | |
}); | |
} | |
return records; | |
} | |
} | |
let d = new DateRange([ | |
"2020-01-01T00:00:00", | |
"2020-02-01T00:00:00", | |
"2020-03-01T00:00:00", | |
]); | |
let v = new Vector([1, 2, 3]); | |
let t = new TimeSeries(d, v); | |
let t1 = new TimeSeries(d, v); | |
let t3 = t1.copy(); | |
// Setting index by position | |
t.setIndexByPos("2020-01-02T00:00:00", 0); | |
// Setting value by | |
t.setValueByIndex("2020-01-02T00:00:00", 23); | |
// Throws error | |
// et series = t.sum(t1); | |
// Works because indices match | |
let series = t.sum(t); | |
let vector = series.values(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment