1 | import { roundD2 } from '@aryth/math';
|
2 | import { isNumeric } from '@typen/num-strict';
|
3 | import { Differentiator } from '@vect/vector-differentiator';
|
4 | import { iterate } from '@vect/vector-mapper';
|
5 |
|
6 |
|
7 | const timeseriesDifferential = function ({
|
8 | dateLabel = 'date',
|
9 | fields,
|
10 | mutate = true
|
11 | }) {
|
12 |
|
13 | const table = mutate ? this : this.copy();
|
14 | const dateIndex = table.coin(dateLabel);
|
15 | const indexes = table.columnIndexes(fields),
|
16 | depth = indexes.length;
|
17 | if (indexes.includes(dateIndex)) indexes.splice(indexes.indexOf(dateIndex), 1);
|
18 | const rows = table.rows;
|
19 | let pv, cv, prevNum, currNum;
|
20 |
|
21 | for (const [prev, curr] of Differentiator.build(rows)) if (equalYear(prev[dateIndex], curr[dateIndex])) {
|
22 | iterate(indexes, i => {
|
23 | prevNum = isNumeric(pv = prev[i]), currNum = isNumeric(cv = curr[i]);
|
24 |
|
25 | if (prevNum) {
|
26 | if (currNum) {
|
27 | prev[i] = roundD2(pv - cv);
|
28 | } else {
|
29 | curr[i] = 0;
|
30 | }
|
31 | } else {
|
32 | if (currNum) {
|
33 | prev[i] = roundD2(0 - cv);
|
34 | } else {
|
35 | prev[i] = null;
|
36 | }
|
37 | }
|
38 | }, depth);
|
39 | }
|
40 |
|
41 | return rows.pop(), table.boot({
|
42 | rows
|
43 | });
|
44 | };
|
45 |
|
46 | const equalYear = (a, b) => a.slice(0, 4) === b.slice(0, 4);
|
47 |
|
48 | export { timeseriesDifferential };
|