xy-scale 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/xy-scale.min.js +1 -1
- package/package.json +1 -1
- package/src/datasets.js +2 -10
- package/src/scale.js +209 -61
- package/test/test.js +6 -5
package/dist/xy-scale.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var XY_Scale;(()=>{"use strict";var e={d:(t
|
|
1
|
+
var XY_Scale;(()=>{"use strict";var e={d:(r,t)=>{for(var n in t)e.o(t,n)&&!e.o(r,n)&&Object.defineProperty(r,n,{enumerable:!0,get:t[n]})},o:(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},r={};e.r(r),e.d(r,{arrayToTimesteps:()=>f,descaleArrayObj:()=>p,parseProductionX:()=>u,parseTrainingXY:()=>i});const t=({arrObj:e,repeat:r={},minmaxRange:t=[0,1],groups:i={},prevConfig:u=null})=>{const p=[...e],f=p.length,c=p[0];if(0===f)return{scaledOutput:[],scaledConfig:{}};let l={};const m=u&&o(u);if(m)s(u,{minmaxRange:t,repeat:r,groups:i,firstRow:c}),l={...u};else{const e=Object.keys(c),n=e.map((e=>r.hasOwnProperty(e)?Math.max(r[e],1):1)),a=n.reduce(((e,r)=>e+r),0);l={rangeMin:t[0],rangeMax:t[1],inputTypes:{},min:{},max:{},uniqueStrIdx:{},groupMinMax:{},repeat:r,groups:i,inputKeyNames:e,outputKeyNames:new Array(a),repeatedKeyNames:n};let s=0;for(let e=0;e<l.inputKeyNames.length;e++)for(let r=0;r<l.repeatedKeyNames[e];r++)l.outputKeyNames[s++]=l.inputKeyNames[e];o(l)}n(l.groups);for(const e of l.inputKeyNames){const r=typeof c[e];if(m){if(!l.inputTypes.hasOwnProperty(e))throw new Error(`Error: A new unknown inputType property "${e}" found.`);if(l.inputTypes[e]!==r)throw new Error(`Error: Current inputType of property "${e}" is not the same as in the prevConfig inputType.`);continue}l.inputTypes[e]=r,"string"===r&&(l.uniqueStrIdx[e]={});const t=a(e,l.groups);t?l.groupMinMax[t]={min:1/0,max:-1/0}:(l.min[e]=1/0,l.max[e]=-1/0)}for(const e of p)for(const r of l.inputKeyNames){let t=e[r];if("string"===l.inputTypes[r]){const n=l.uniqueStrIdx[r];n.hasOwnProperty(t)||(n[t]=Object.keys(n).length),t=n[t],e[r]=t}else"boolean"===l.inputTypes[r]&&(e[r]=Number(t));const n=a(r,l.groups);n?(l.groupMinMax[n].min=Math.min(l.groupMinMax[n].min,t),l.groupMinMax[n].max=Math.max(l.groupMinMax[n].max,t)):(l.min[r]=Math.min(l.min[r],t),l.max[r]=Math.max(l.max[r],t))}const g=new Array(f);for(let e=0;e<f;e++){const r=p[e],t=new Array(l.outputKeyNames.length);let n=0;for(let e=0;e<l.inputKeyNames.length;e++){const o=l.inputKeyNames[e],s=r[o],i=a(o,l.groups);let u,p;i?(u=l.groupMinMax[i].min,p=l.groupMinMax[i].max):(u=l.min[o],p=l.max[o]);const f=p!==u?l.rangeMin+(s-u)/(p-u)*(l.rangeMax-l.rangeMin):l.rangeMin,c=l.repeatedKeyNames[e];for(let e=0;e<c;e++)t[n++]=f}g[e]=t}return{scaledOutput:g,scaledConfig:l}},n=e=>{const r=new Set,t=[];for(const[n,a]of Object.entries(e))r.add(n),t.push(n),a.forEach((e=>{r.add(e),t.push(e)}));if(r.size!==t.length)throw new Error("Duplicate value found between properties in validateUniqueProperties function.")},a=(e,r)=>{for(const[t,n]of Object.entries(r))if(n.includes(e))return t;return null},o=e=>{if(!e)return!1;const r=["rangeMin","rangeMax","inputTypes","min","max","uniqueStrIdx","groupMinMax","repeat","groups","inputKeyNames","outputKeyNames","repeatedKeyNames"];for(const t of r)if(!e.hasOwnProperty(t))throw new Error(`Missing key "${t}" in config.`);const{rangeMin:t,rangeMax:n,inputTypes:a,min:o,max:s,uniqueStrIdx:i,groupMinMax:u,repeat:p,groups:f,inputKeyNames:c,outputKeyNames:l,repeatedKeyNames:m}=e;if("number"!=typeof t||"number"!=typeof n)throw new Error("rangeMin and rangeMax must be numbers.");if(t>=n)throw new Error("rangeMin must be less than rangeMax.");const g=e=>"object"==typeof e&&null!==e&&!Array.isArray(e);if(!g(a))throw new Error("inputTypes must be an object.");if(!g(o))throw new Error("min must be an object.");if(!g(s))throw new Error("max must be an object.");if(!g(i))throw new Error("uniqueStrIdx must be an object.");if(!g(u))throw new Error("groupMinMax must be an object.");if(!g(p))throw new Error("repeat must be an object.");if(!g(f))throw new Error("groups must be an object.");if(!Array.isArray(c))throw new Error("inputKeyNames must be an array.");if(!Array.isArray(l))throw new Error("outputKeyNames must be an array.");if(!Array.isArray(m))throw new Error("repeatedKeyNames must be an array.");return!0},s=(e,{minmaxRange:r,repeat:t,groups:n,firstRow:a})=>{if(e.rangeMin!==r[0]||e.rangeMax!==r[1])throw new Error('"prevConfig.minmaxRange" is not equal "minmaxRange".');if(JSON.stringify(e.inputKeyNames)!==JSON.stringify(Object.keys(a)))throw new Error('"prevConfig.inputKeyNames" structure does not match "Object.keys(firstRow)" structure. The order of keys is important.');if(JSON.stringify(e.repeat)!==JSON.stringify(t))throw new Error('"prevConfig.repeat" structure does not match "repeat" structure. The order of keys is important.');if(JSON.stringify(e.groups)!==JSON.stringify(n))throw new Error('"prevConfig.groups" structure does not match "groups" structure. The order of keys is important.');return!0},i=({arrObj:e,trainingSplit:r=.8,repeat:n={},yCallbackFunc:a,xCallbackFunc:o,validateRows:s=e=>e,groups:i,shuffle:u=!1,minmaxRange:p,balancing:f="",state:c={}})=>{let l=[],m=[];for(let r=0;r<e.length;r++){if(!s(e[r]))continue;const t=o({objRow:e,index:r,state:c}),n=a({objRow:e,index:r,state:c});null!=t&&null!=n&&(l.push(t),m.push(n))}if(u){const{shuffledX:e,shuffledY:r}=((e,r)=>{if(e.length!==r.length)throw new Error("X and Y arrays must have the same length");const t=Array.from({length:e.length},((e,r)=>r));for(let e=t.length-1;e>0;e--){const r=Math.floor(Math.random()*(e+1));[t[e],t[r]]=[t[r],t[e]]}return{shuffledX:t.map((r=>e[r])),shuffledY:t.map((e=>r[e]))}})(l,m);l=e,m=r}let{scaledOutput:g,scaledConfig:y}=t({arrObj:l,repeat:n,groups:i,minmaxRange:p}),{scaledOutput:h,scaledConfig:d}=t({arrObj:m,repeat:n,groups:i,minmaxRange:p});const w=Math.floor(g.length*r);let b=g.slice(0,w),x=h.slice(0,w),M=g.slice(w),O=h.slice(w);if(f){let e;if("oversample"===f)e=((e,r)=>{const t={},n={};r.forEach(((a,o)=>{t[a]||(t[a]=0,n[a]=[]),t[a]++,n[a].push([e[o],r[o]])}));const a=Math.max(...Object.values(t)),o=[],s=[];return Object.keys(n).forEach((e=>{const r=n[e],t=r.length;for(let e=0;e<a;e++){const n=r[e%t];o.push(n[0]),s.push(n[1])}})),{X:o,Y:s}})(b,x),b=e.X,x=e.Y;else{if("undersample"!==f)throw Error('balancing argument only accepts "false", "oversample" and "undersample". Defaults to "false".');e=((e,r)=>{const t={},n={};r.forEach(((a,o)=>{t[a]||(t[a]=0,n[a]=[]),t[a]++,n[a].push([e[o],r[o]])}));const a=Math.min(...Object.values(t)),o=[],s=[];return Object.keys(n).forEach((e=>{const r=n[e];for(let e=0;e<a;e++){const t=r[e];o.push(t[0]),s.push(t[1])}})),{X:o,Y:s}})(b,x),b=e.X,x=e.Y}}return{trainX:b,trainY:x,testX:M,testY:O,configX:y,configY:d}},u=({arrObj:e,repeat:r={},xCallbackFunc:n,validateRows:a=e=>e,groups:o,shuffle:s=!1,minmaxRange:i,state:u={}})=>{let p=[];for(let r=0;r<e.length;r++){if(!a(e[r]))continue;const t=n({objRow:e,index:r,state:u});t&&p.push(t)}s&&(p=(e=>{const r=[...e];for(let e=r.length-1;e>0;e--){const t=Math.floor(Math.random()*(e+1));[r[e],r[t]]=[r[t],r[e]]}return r})(p));const{scaledOutput:f,scaledConfig:c}=t({arrObj:p,repeat:r,groups:o,minmaxRange:i});return{X:f,configX:c,keyNamesX}},p=({scaled:e,config:r,keyNames:t})=>{const{min:n,max:a,std:o,mean:s,approach:i,inputTypes:u,uniqueStringIndexes:p}=r;return e.map((e=>{const r={};let f=0;for(const c of Object.keys(n)){const l=i[c],m=n[c],g=a[c],y=s[c],h=o[c],d=t.filter((e=>e===c)).length;let w=0;for(let r=0;r<d;r++)w+=e[f++];const b=w/d;let x;if("normalization"===l?x=b*(g-m)+m:"standardization"===l&&(x=b*h+y),"string"===u[c]){const e=Object.keys(p[c]).find((e=>p[c][e]===x));x=void 0!==e?e:x}r[c]=x}return r}))},f=(e,r)=>{if(0===r)return e;if(r<0)throw new Error("timeSteps must be greater than 0");const t=[];for(let n=0;n<=e.length-r;n++)t.push(e.slice(n,n+r));return t};XY_Scale=r})();
|
package/package.json
CHANGED
package/src/datasets.js
CHANGED
|
@@ -41,15 +41,12 @@ export const parseTrainingXY = ({
|
|
|
41
41
|
|
|
42
42
|
let {
|
|
43
43
|
scaledOutput: scaledX,
|
|
44
|
-
scaledConfig: configX
|
|
45
|
-
scaledKeyNames: keyNamesX
|
|
46
|
-
|
|
44
|
+
scaledConfig: configX
|
|
47
45
|
} = scaleArrayObj({arrObj: X, repeat, groups, minmaxRange})
|
|
48
46
|
|
|
49
47
|
let {
|
|
50
48
|
scaledOutput: scaledY,
|
|
51
49
|
scaledConfig: configY,
|
|
52
|
-
scaledKeyNames: keyNamesY
|
|
53
50
|
} = scaleArrayObj({arrObj: Y, repeat, groups, minmaxRange})
|
|
54
51
|
|
|
55
52
|
|
|
@@ -93,11 +90,8 @@ export const parseTrainingXY = ({
|
|
|
93
90
|
trainY,
|
|
94
91
|
testX,
|
|
95
92
|
testY,
|
|
96
|
-
|
|
97
93
|
configX,
|
|
98
|
-
keyNamesX,
|
|
99
94
|
configY,
|
|
100
|
-
keyNamesY
|
|
101
95
|
};
|
|
102
96
|
};
|
|
103
97
|
|
|
@@ -133,9 +127,7 @@ export const parseProductionX = ({
|
|
|
133
127
|
// Scale X
|
|
134
128
|
const {
|
|
135
129
|
scaledOutput: scaledX,
|
|
136
|
-
scaledConfig: configX
|
|
137
|
-
scaledKeyNames: keyNamesX
|
|
138
|
-
|
|
130
|
+
scaledConfig: configX
|
|
139
131
|
} = scaleArrayObj({arrObj: X, repeat, groups, minmaxRange})
|
|
140
132
|
|
|
141
133
|
|
package/src/scale.js
CHANGED
|
@@ -1,120 +1,155 @@
|
|
|
1
|
-
export const scaleArrayObj = ({ arrObj, repeat = {}, minmaxRange = [0, 1], groups = {} }) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export const scaleArrayObj = ({ arrObj, repeat = {}, minmaxRange = [0, 1], groups = {}, prevConfig = null }) => {
|
|
2
|
+
|
|
3
|
+
const arrObjClone = [...arrObj]
|
|
4
|
+
const n = arrObjClone.length;
|
|
5
|
+
const firstRow = arrObjClone[0]
|
|
5
6
|
|
|
6
7
|
if (n === 0) {
|
|
7
8
|
return {
|
|
8
9
|
scaledOutput: [],
|
|
9
|
-
scaledConfig: {}
|
|
10
|
-
keyNames: []
|
|
10
|
+
scaledConfig: {}
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
let config = {}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const isValidPrevConfig = prevConfig && validateConfig(prevConfig)
|
|
17
|
+
|
|
18
|
+
if(isValidPrevConfig)
|
|
19
|
+
{
|
|
20
|
+
validateCurrPrevConfig(prevConfig, {minmaxRange, repeat, groups, firstRow})
|
|
21
|
+
config = {...prevConfig}
|
|
18
22
|
}
|
|
23
|
+
else
|
|
24
|
+
{
|
|
25
|
+
const inputKeyNames = Object.keys(firstRow);
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
const repeatedKeyNames = inputKeyNames.map(key => {
|
|
28
|
+
return repeat.hasOwnProperty(key) ? Math.max(repeat[key], 1) : 1;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const countRepeatedKeyNames = repeatedKeyNames.reduce((sum, rep) => sum + rep, 0);
|
|
32
|
+
|
|
33
|
+
config = {
|
|
34
|
+
rangeMin: minmaxRange[0],
|
|
35
|
+
rangeMax: minmaxRange[1],
|
|
36
|
+
inputTypes: {},
|
|
37
|
+
min: {},
|
|
38
|
+
max: {},
|
|
39
|
+
uniqueStrIdx: {},
|
|
40
|
+
groupMinMax: {},
|
|
41
|
+
repeat,
|
|
42
|
+
groups,
|
|
43
|
+
inputKeyNames,
|
|
44
|
+
outputKeyNames: new Array(countRepeatedKeyNames),
|
|
45
|
+
repeatedKeyNames,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let keyNamesIdx = 0;
|
|
21
49
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
50
|
+
for (let i = 0; i < config.inputKeyNames.length; i++) {
|
|
51
|
+
for (let w = 0; w < config.repeatedKeyNames[i]; w++) {
|
|
52
|
+
config.outputKeyNames[keyNamesIdx++] = config.inputKeyNames[i];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
25
55
|
|
|
26
|
-
|
|
56
|
+
validateConfig(config)
|
|
27
57
|
|
|
28
|
-
const outputKeyNames = new Array(totalColumns);
|
|
29
|
-
let idx = 0;
|
|
30
|
-
for (let i = 0; i < keyNames.length; i++) {
|
|
31
|
-
for (let w = 0; w < repeatedKeyNames[i]; w++) {
|
|
32
|
-
outputKeyNames[idx++] = keyNames[i];
|
|
33
|
-
}
|
|
34
58
|
}
|
|
35
59
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const uniqueStringIndexes = {};
|
|
40
|
-
const groupMinMax = {};
|
|
60
|
+
validateUniqueProperties(config.groups);
|
|
61
|
+
|
|
62
|
+
for (const key of config.inputKeyNames) {
|
|
41
63
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
const firstType = typeof firstRow[key]
|
|
65
|
+
|
|
66
|
+
if(isValidPrevConfig)
|
|
67
|
+
{
|
|
68
|
+
if(!config.inputTypes.hasOwnProperty(key))
|
|
69
|
+
{
|
|
70
|
+
// If prevConfig is set, no new inputTypes can be introduced
|
|
71
|
+
throw new Error(`Error: A new unknown inputType property "${key}" found.`)
|
|
72
|
+
}
|
|
73
|
+
if(config.inputTypes[key] !== firstType)
|
|
74
|
+
{
|
|
75
|
+
//is prevConfig is set the types of "typeof firstRow[key]" and config.inputTypes[key] must be the same
|
|
76
|
+
throw new Error(`Error: Current inputType of property "${key}" is not the same as in the prevConfig inputType.`)
|
|
77
|
+
}
|
|
45
78
|
|
|
46
|
-
|
|
47
|
-
uniqueStringIndexes[key] = {};
|
|
79
|
+
continue;
|
|
48
80
|
}
|
|
49
81
|
|
|
82
|
+
config.inputTypes[key] = firstType;
|
|
83
|
+
|
|
84
|
+
if (firstType === 'string') {
|
|
85
|
+
config.uniqueStrIdx[key] = {};
|
|
86
|
+
}
|
|
50
87
|
|
|
88
|
+
const thisGroup = findGroup(key, config.groups);
|
|
51
89
|
|
|
52
|
-
const thisGroup = findGroup(key, groups);
|
|
53
90
|
if (thisGroup) {
|
|
54
|
-
|
|
55
|
-
groupMinMax[thisGroup] = { min: Infinity, max: -Infinity };
|
|
56
|
-
}
|
|
91
|
+
config.groupMinMax[thisGroup] = { min: Infinity, max: -Infinity };
|
|
57
92
|
} else
|
|
58
93
|
{
|
|
59
|
-
min[key] = Infinity;
|
|
60
|
-
max[key] = -Infinity;
|
|
94
|
+
config.min[key] = Infinity;
|
|
95
|
+
config.max[key] = -Infinity;
|
|
61
96
|
}
|
|
62
97
|
}
|
|
63
98
|
|
|
64
|
-
for (const obj of
|
|
65
|
-
for (const key of
|
|
99
|
+
for (const obj of arrObjClone) {
|
|
100
|
+
for (const key of config.inputKeyNames) {
|
|
66
101
|
let value = obj[key];
|
|
67
102
|
|
|
68
|
-
if (inputTypes[key] === 'string') {
|
|
69
|
-
const uniqueIndexes =
|
|
103
|
+
if (config.inputTypes[key] === 'string') {
|
|
104
|
+
const uniqueIndexes = config.uniqueStrIdx[key];
|
|
70
105
|
if (!uniqueIndexes.hasOwnProperty(value)) {
|
|
71
106
|
uniqueIndexes[value] = Object.keys(uniqueIndexes).length;
|
|
72
107
|
}
|
|
73
108
|
value = uniqueIndexes[value];
|
|
74
109
|
obj[key] = value;
|
|
75
|
-
} else if (inputTypes[key] === 'boolean') {
|
|
110
|
+
} else if (config.inputTypes[key] === 'boolean') {
|
|
76
111
|
obj[key] = Number(value);
|
|
77
112
|
}
|
|
78
113
|
|
|
79
|
-
const thisGroup = findGroup(key, groups);
|
|
114
|
+
const thisGroup = findGroup(key, config.groups);
|
|
80
115
|
|
|
81
116
|
if (thisGroup) {
|
|
82
|
-
groupMinMax[thisGroup].min = Math.min(groupMinMax[thisGroup].min, value);
|
|
83
|
-
groupMinMax[thisGroup].max = Math.max(groupMinMax[thisGroup].max, value);
|
|
117
|
+
config.groupMinMax[thisGroup].min = Math.min(config.groupMinMax[thisGroup].min, value);
|
|
118
|
+
config.groupMinMax[thisGroup].max = Math.max(config.groupMinMax[thisGroup].max, value);
|
|
84
119
|
} else {
|
|
85
|
-
min[key] = Math.min(min[key], value);
|
|
86
|
-
max[key] = Math.max(max[key], value);
|
|
120
|
+
config.min[key] = Math.min(config.min[key], value);
|
|
121
|
+
config.max[key] = Math.max(config.max[key], value);
|
|
87
122
|
}
|
|
88
123
|
}
|
|
89
124
|
}
|
|
90
125
|
|
|
91
126
|
const scaledOutput = new Array(n);
|
|
92
127
|
for (let i = 0; i < n; i++) {
|
|
93
|
-
const obj =
|
|
94
|
-
const scaledRow = new Array(
|
|
128
|
+
const obj = arrObjClone[i];
|
|
129
|
+
const scaledRow = new Array(config.outputKeyNames.length);
|
|
95
130
|
let idx = 0;
|
|
96
131
|
|
|
97
|
-
for (let j = 0; j <
|
|
98
|
-
const key =
|
|
132
|
+
for (let j = 0; j < config.inputKeyNames.length; j++) {
|
|
133
|
+
const key = config.inputKeyNames[j];
|
|
99
134
|
const value = obj[key];
|
|
100
135
|
|
|
101
|
-
const thisGroup = findGroup(key, groups);
|
|
136
|
+
const thisGroup = findGroup(key, config.groups);
|
|
102
137
|
let minValue, maxValue;
|
|
103
138
|
|
|
104
139
|
if (thisGroup) {
|
|
105
|
-
minValue = groupMinMax[thisGroup].min;
|
|
106
|
-
maxValue = groupMinMax[thisGroup].max;
|
|
140
|
+
minValue = config.groupMinMax[thisGroup].min;
|
|
141
|
+
maxValue = config.groupMinMax[thisGroup].max;
|
|
107
142
|
} else {
|
|
108
|
-
minValue = min[key];
|
|
109
|
-
maxValue = max[key];
|
|
143
|
+
minValue = config.min[key];
|
|
144
|
+
maxValue = config.max[key];
|
|
110
145
|
}
|
|
111
146
|
|
|
112
147
|
const scaledValue =
|
|
113
148
|
maxValue !== minValue
|
|
114
|
-
? rangeMin + ((value - minValue) / (maxValue - minValue)) * (rangeMax - rangeMin)
|
|
115
|
-
: rangeMin;
|
|
149
|
+
? config.rangeMin + ((value - minValue) / (maxValue - minValue)) * (config.rangeMax - config.rangeMin)
|
|
150
|
+
: config.rangeMin;
|
|
116
151
|
|
|
117
|
-
const rep = repeatedKeyNames[j];
|
|
152
|
+
const rep = config.repeatedKeyNames[j];
|
|
118
153
|
|
|
119
154
|
for (let w = 0; w < rep; w++) {
|
|
120
155
|
scaledRow[idx++] = scaledValue;
|
|
@@ -124,15 +159,15 @@ export const scaleArrayObj = ({ arrObj, repeat = {}, minmaxRange = [0, 1], group
|
|
|
124
159
|
scaledOutput[i] = scaledRow;
|
|
125
160
|
}
|
|
126
161
|
|
|
127
|
-
|
|
162
|
+
|
|
128
163
|
|
|
129
164
|
return {
|
|
130
165
|
scaledOutput,
|
|
131
|
-
scaledConfig
|
|
132
|
-
scaledKeyNames: outputKeyNames
|
|
166
|
+
scaledConfig: config
|
|
133
167
|
};
|
|
134
168
|
};
|
|
135
169
|
|
|
170
|
+
|
|
136
171
|
const validateUniqueProperties = obj => {
|
|
137
172
|
const uniqueValues = new Set();
|
|
138
173
|
const allValues = [];
|
|
@@ -160,3 +195,116 @@ const findGroup = (key, groups) => {
|
|
|
160
195
|
}
|
|
161
196
|
return null;
|
|
162
197
|
};
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
const validateConfig = config => {
|
|
201
|
+
|
|
202
|
+
if(!config) return false
|
|
203
|
+
|
|
204
|
+
const requiredKeys = [
|
|
205
|
+
"rangeMin",
|
|
206
|
+
"rangeMax",
|
|
207
|
+
"inputTypes",
|
|
208
|
+
"min",
|
|
209
|
+
"max",
|
|
210
|
+
"uniqueStrIdx",
|
|
211
|
+
"groupMinMax",
|
|
212
|
+
"repeat",
|
|
213
|
+
"groups",
|
|
214
|
+
"inputKeyNames",
|
|
215
|
+
"outputKeyNames",
|
|
216
|
+
"repeatedKeyNames"
|
|
217
|
+
];
|
|
218
|
+
|
|
219
|
+
// Check for missing keys
|
|
220
|
+
for (const key of requiredKeys) {
|
|
221
|
+
if (!config.hasOwnProperty(key)) {
|
|
222
|
+
throw new Error(`Missing key "${key}" in config.`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const {
|
|
227
|
+
rangeMin,
|
|
228
|
+
rangeMax,
|
|
229
|
+
inputTypes,
|
|
230
|
+
min,
|
|
231
|
+
max,
|
|
232
|
+
uniqueStrIdx,
|
|
233
|
+
groupMinMax,
|
|
234
|
+
repeat,
|
|
235
|
+
groups,
|
|
236
|
+
inputKeyNames,
|
|
237
|
+
outputKeyNames,
|
|
238
|
+
repeatedKeyNames
|
|
239
|
+
} = config;
|
|
240
|
+
|
|
241
|
+
// Validate rangeMin and rangeMax are numbers and in proper order
|
|
242
|
+
if (typeof rangeMin !== 'number' || typeof rangeMax !== 'number') {
|
|
243
|
+
throw new Error("rangeMin and rangeMax must be numbers.");
|
|
244
|
+
}
|
|
245
|
+
if (rangeMin >= rangeMax) {
|
|
246
|
+
throw new Error("rangeMin must be less than rangeMax.");
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Helper to check if a value is a plain object (and not null or an array)
|
|
250
|
+
const isPlainObject = (obj) => typeof obj === 'object' && obj !== null && !Array.isArray(obj);
|
|
251
|
+
|
|
252
|
+
if (!isPlainObject(inputTypes)) {
|
|
253
|
+
throw new Error("inputTypes must be an object.");
|
|
254
|
+
}
|
|
255
|
+
if (!isPlainObject(min)) {
|
|
256
|
+
throw new Error("min must be an object.");
|
|
257
|
+
}
|
|
258
|
+
if (!isPlainObject(max)) {
|
|
259
|
+
throw new Error("max must be an object.");
|
|
260
|
+
}
|
|
261
|
+
if (!isPlainObject(uniqueStrIdx)) {
|
|
262
|
+
throw new Error("uniqueStrIdx must be an object.");
|
|
263
|
+
}
|
|
264
|
+
if (!isPlainObject(groupMinMax)) {
|
|
265
|
+
throw new Error("groupMinMax must be an object.");
|
|
266
|
+
}
|
|
267
|
+
if (!isPlainObject(repeat)) {
|
|
268
|
+
throw new Error("repeat must be an object.");
|
|
269
|
+
}
|
|
270
|
+
if (!isPlainObject(groups)) {
|
|
271
|
+
throw new Error("groups must be an object.");
|
|
272
|
+
}
|
|
273
|
+
if(!Array.isArray(inputKeyNames))
|
|
274
|
+
{
|
|
275
|
+
throw new Error("inputKeyNames must be an array.");
|
|
276
|
+
}
|
|
277
|
+
if(!Array.isArray(outputKeyNames))
|
|
278
|
+
{
|
|
279
|
+
throw new Error("outputKeyNames must be an array.");
|
|
280
|
+
}
|
|
281
|
+
if(!Array.isArray(repeatedKeyNames))
|
|
282
|
+
{
|
|
283
|
+
throw new Error("repeatedKeyNames must be an array.");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const validateCurrPrevConfig = (prevConfig, {minmaxRange, repeat, groups, firstRow}) => {
|
|
290
|
+
|
|
291
|
+
if(prevConfig.rangeMin !== minmaxRange[0] || prevConfig.rangeMax !== minmaxRange[1])
|
|
292
|
+
{
|
|
293
|
+
throw new Error(`"prevConfig.minmaxRange" is not equal "minmaxRange".`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
//it is important o keep the same key order
|
|
297
|
+
if (JSON.stringify(prevConfig.inputKeyNames) !== JSON.stringify(Object.keys(firstRow))) {
|
|
298
|
+
throw new Error(`"prevConfig.inputKeyNames" structure does not match "Object.keys(firstRow)" structure. The order of keys is important.`);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (JSON.stringify(prevConfig.repeat) !== JSON.stringify(repeat)) {
|
|
302
|
+
throw new Error(`"prevConfig.repeat" structure does not match "repeat" structure. The order of keys is important.`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (JSON.stringify(prevConfig.groups) !== JSON.stringify(groups)) {
|
|
306
|
+
throw new Error(`"prevConfig.groups" structure does not match "groups" structure. The order of keys is important.`);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return true
|
|
310
|
+
}
|
package/test/test.js
CHANGED
|
@@ -15,9 +15,10 @@ const test = async () => {
|
|
|
15
15
|
//returning null or undefined will exclude current row X and Y from training
|
|
16
16
|
if(typeof prev === 'undefined') return null
|
|
17
17
|
|
|
18
|
-
const { open, high, low, close, volume } = curr
|
|
18
|
+
const { open, high, low, close, volume, date } = curr
|
|
19
19
|
|
|
20
20
|
return {
|
|
21
|
+
date,
|
|
21
22
|
open,
|
|
22
23
|
high,
|
|
23
24
|
low,
|
|
@@ -82,10 +83,10 @@ const test = async () => {
|
|
|
82
83
|
const inputX = tf.tensor3d(timeSteppedTrainX, [timeSteppedTrainX.length, timeSteps, colsX])
|
|
83
84
|
const targetY = tf.tensor2d(trimedTrainY, [trimedTrainY.length, colsY])
|
|
84
85
|
|
|
85
|
-
console.log('trainX', trainX[trainX.length - 1])
|
|
86
|
-
console.log('configX',
|
|
87
|
-
console.log('inputX', inputX)
|
|
88
|
-
console.log('inputX', targetY)
|
|
86
|
+
//console.log('trainX', trainX[trainX.length - 1])
|
|
87
|
+
console.log('configX', configX)
|
|
88
|
+
//console.log('inputX', inputX)
|
|
89
|
+
//console.log('inputX', targetY)
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
test()
|