xy-scale 1.1.0 → 1.1.1
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/package.json +1 -1
- package/src/scale.js +13 -32
package/package.json
CHANGED
package/src/scale.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
4
2
|
|
|
5
|
-
if(forceScaling !== null
|
|
6
|
-
|
|
7
|
-
throw Error('forceScalling should be null, "normalization" or "standardization"')
|
|
3
|
+
if (forceScaling !== null && forceScaling !== 'normalization' && forceScaling !== 'standardization') {
|
|
4
|
+
throw Error('forceScaling should be null, "normalization" or "standardization"');
|
|
8
5
|
}
|
|
9
6
|
|
|
10
7
|
const n = arrObj.length;
|
|
11
8
|
|
|
12
9
|
if (n === 0) {
|
|
13
|
-
// If the input array is empty, return empty outputs
|
|
14
10
|
return {
|
|
15
11
|
scaledOutput: [],
|
|
16
12
|
scaledConfig: {},
|
|
@@ -18,36 +14,22 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
18
14
|
};
|
|
19
15
|
}
|
|
20
16
|
|
|
21
|
-
// Get the feature names (keys) from the first object
|
|
22
17
|
const keyNames = Object.keys(arrObj[0]);
|
|
23
18
|
|
|
24
|
-
// **Loop 1: Compute weights for each keyName**
|
|
25
19
|
const keyNameWeights = keyNames.map(key => {
|
|
26
|
-
|
|
27
|
-
const weight = weights[key];
|
|
28
|
-
if (weight <= 0) {
|
|
29
|
-
throw new Error(`Weight for key "${key}" must be positive.`);
|
|
30
|
-
}
|
|
31
|
-
return weight;
|
|
32
|
-
} else {
|
|
33
|
-
return 1; // Default weight
|
|
34
|
-
}
|
|
20
|
+
return weights.hasOwnProperty(key) ? Math.max(weights[key], 1) : 1;
|
|
35
21
|
});
|
|
36
22
|
|
|
37
23
|
const totalColumns = keyNameWeights.reduce((sum, weight) => sum + weight, 0);
|
|
38
24
|
|
|
39
|
-
// **Loop 2: Build the new keyNames array with weights applied**
|
|
40
25
|
const outputKeyNames = new Array(totalColumns);
|
|
41
26
|
let idx = 0;
|
|
42
27
|
for (let i = 0; i < keyNames.length; i++) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
for (let w = 0; w < weight; w++) {
|
|
46
|
-
outputKeyNames[idx++] = key;
|
|
28
|
+
for (let w = 0; w < keyNameWeights[i]; w++) {
|
|
29
|
+
outputKeyNames[idx++] = keyNames[i];
|
|
47
30
|
}
|
|
48
31
|
}
|
|
49
32
|
|
|
50
|
-
// Initialize variables for scaling
|
|
51
33
|
const inputTypes = {};
|
|
52
34
|
const min = {};
|
|
53
35
|
const max = {};
|
|
@@ -57,7 +39,6 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
57
39
|
const uniqueStringIndexes = {};
|
|
58
40
|
const counts = {};
|
|
59
41
|
|
|
60
|
-
// **Loop 3: Initialize variables for each key**
|
|
61
42
|
for (const key of keyNames) {
|
|
62
43
|
const firstValue = arrObj[0][key];
|
|
63
44
|
inputTypes[key] = typeof firstValue;
|
|
@@ -73,7 +54,6 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
73
54
|
counts[key] = 0;
|
|
74
55
|
}
|
|
75
56
|
|
|
76
|
-
// **Loop 4: Single pass to process data**
|
|
77
57
|
for (const obj of arrObj) {
|
|
78
58
|
for (const key of keyNames) {
|
|
79
59
|
let value = obj[key];
|
|
@@ -84,11 +64,11 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
84
64
|
uniqueIndexes[value] = Object.keys(uniqueIndexes).length;
|
|
85
65
|
}
|
|
86
66
|
value = uniqueIndexes[value];
|
|
87
|
-
obj[key] = value;
|
|
67
|
+
obj[key] = value;
|
|
88
68
|
}
|
|
89
69
|
|
|
90
|
-
|
|
91
|
-
|
|
70
|
+
min[key] = Math.min(min[key], value);
|
|
71
|
+
max[key] = Math.max(max[key], value);
|
|
92
72
|
|
|
93
73
|
counts[key]++;
|
|
94
74
|
const delta = value - mean[key];
|
|
@@ -97,20 +77,19 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
97
77
|
}
|
|
98
78
|
}
|
|
99
79
|
|
|
100
|
-
// **Loop 5: Finalize standard deviation and decide scaling approach**
|
|
101
80
|
const std = {};
|
|
102
81
|
for (const key of keyNames) {
|
|
103
82
|
std[key] = counts[key] > 1 ? Math.sqrt(M2[key] / (counts[key] - 1)) : 0;
|
|
104
83
|
|
|
105
|
-
// Apply forceScaling if specified, else use automatic selection
|
|
106
84
|
if (forceScaling === 'normalization' || forceScaling === 'standardization') {
|
|
107
85
|
approach[key] = forceScaling;
|
|
86
|
+
} else if (min[key] === 0 && max[key] === 1) {
|
|
87
|
+
approach[key] = 'none'; // No scaling required
|
|
108
88
|
} else {
|
|
109
89
|
approach[key] = std[key] < 1 ? 'normalization' : 'standardization';
|
|
110
90
|
}
|
|
111
91
|
}
|
|
112
92
|
|
|
113
|
-
// **Loop 6: Create scaled and reweighted output**
|
|
114
93
|
const scaledOutput = new Array(n);
|
|
115
94
|
for (let i = 0; i < n; i++) {
|
|
116
95
|
const obj = arrObj[i];
|
|
@@ -125,7 +104,9 @@ export const scaleArrayObj = ({arrObj, weights = {}, forceScaling = null}) => {
|
|
|
125
104
|
const stdValue = std[key];
|
|
126
105
|
|
|
127
106
|
let scaledValue;
|
|
128
|
-
if (approach[key] === '
|
|
107
|
+
if (approach[key] === 'none') {
|
|
108
|
+
scaledValue = value; // No scaling
|
|
109
|
+
} else if (approach[key] === 'normalization') {
|
|
129
110
|
scaledValue = maxValue !== minValue ? (value - minValue) / (maxValue - minValue) : 0;
|
|
130
111
|
} else {
|
|
131
112
|
scaledValue = stdValue !== 0 ? (value - meanValue) / stdValue : 0;
|