datly 0.0.2 → 0.0.3
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/README.MD +1773 -2386
- package/dist/datly.cjs +1 -1
- package/dist/datly.mjs +1 -1
- package/dist/datly.umd.js +1 -1
- package/package.json +3 -3
- package/src/code.js +2466 -0
- package/src/index.js +236 -480
- package/src/plot.js +609 -0
- package/src/core/dataLoader.js +0 -407
- package/src/core/utils.js +0 -306
- package/src/core/validator.js +0 -205
- package/src/dataviz/index.js +0 -1566
- package/src/descriptive/centralTendency.js +0 -208
- package/src/descriptive/dispersion.js +0 -273
- package/src/descriptive/position.js +0 -268
- package/src/descriptive/shape.js +0 -336
- package/src/inferential/confidenceIntervals.js +0 -561
- package/src/inferential/hypothesisTesting.js +0 -527
- package/src/inferential/normalityTests.js +0 -587
- package/src/insights/autoAnalyser.js +0 -685
- package/src/insights/interpreter.js +0 -543
- package/src/insights/patternDetector.js +0 -897
- package/src/insights/reportGenerator.js +0 -1072
- package/src/ml/ClassificationMetrics.js +0 -336
- package/src/ml/DecisionTree.js +0 -412
- package/src/ml/KNearestNeighbors.js +0 -317
- package/src/ml/LinearRegression.js +0 -179
- package/src/ml/LogisticRegression.js +0 -396
- package/src/ml/MachineLearning.js +0 -490
- package/src/ml/NaiveBayes.js +0 -296
- package/src/ml/RandomForest.js +0 -323
- package/src/ml/SupportVectorMachine.js +0 -299
- package/src/ml/baseModel.js +0 -106
- package/src/multivariate/correlation.js +0 -653
- package/src/multivariate/regression.js +0 -660
@@ -1,268 +0,0 @@
|
|
1
|
-
class Position {
|
2
|
-
quantile(column, q) {
|
3
|
-
if (!Array.isArray(column) || column.length === 0) {
|
4
|
-
throw new Error('Column must be a non-empty array');
|
5
|
-
}
|
6
|
-
|
7
|
-
if (typeof q !== 'number' || q < 0 || q > 1) {
|
8
|
-
throw new Error('Quantile must be between 0 and 1');
|
9
|
-
}
|
10
|
-
|
11
|
-
const validValues = column.filter(val =>
|
12
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
13
|
-
);
|
14
|
-
|
15
|
-
if (validValues.length === 0) {
|
16
|
-
throw new Error('No valid numeric values found');
|
17
|
-
}
|
18
|
-
|
19
|
-
const sorted = validValues.sort((a, b) => a - b);
|
20
|
-
const index = (sorted.length - 1) * q;
|
21
|
-
const lower = Math.floor(index);
|
22
|
-
const upper = Math.ceil(index);
|
23
|
-
const weight = index % 1;
|
24
|
-
|
25
|
-
if (lower === upper) {
|
26
|
-
return sorted[lower];
|
27
|
-
}
|
28
|
-
|
29
|
-
return sorted[lower] * (1 - weight) + sorted[upper] * weight;
|
30
|
-
}
|
31
|
-
|
32
|
-
percentile(column, p) {
|
33
|
-
if (typeof p !== 'number' || p < 0 || p > 100) {
|
34
|
-
throw new Error('Percentile must be between 0 and 100');
|
35
|
-
}
|
36
|
-
|
37
|
-
return this.quantile(column, p / 100);
|
38
|
-
}
|
39
|
-
|
40
|
-
quartiles(column) {
|
41
|
-
return {
|
42
|
-
q1: this.quantile(column, 0.25),
|
43
|
-
q2: this.quantile(column, 0.5),
|
44
|
-
q3: this.quantile(column, 0.75),
|
45
|
-
iqr: this.quantile(column, 0.75) - this.quantile(column, 0.25)
|
46
|
-
};
|
47
|
-
}
|
48
|
-
|
49
|
-
quintiles(column) {
|
50
|
-
return {
|
51
|
-
q1: this.quantile(column, 0.2),
|
52
|
-
q2: this.quantile(column, 0.4),
|
53
|
-
q3: this.quantile(column, 0.6),
|
54
|
-
q4: this.quantile(column, 0.8)
|
55
|
-
};
|
56
|
-
}
|
57
|
-
|
58
|
-
deciles(column) {
|
59
|
-
const deciles = {};
|
60
|
-
for (let i = 1; i <= 9; i++) {
|
61
|
-
deciles[`d${i}`] = this.quantile(column, i / 10);
|
62
|
-
}
|
63
|
-
return deciles;
|
64
|
-
}
|
65
|
-
|
66
|
-
percentileRank(column, value) {
|
67
|
-
if (!Array.isArray(column) || column.length === 0) {
|
68
|
-
throw new Error('Column must be a non-empty array');
|
69
|
-
}
|
70
|
-
|
71
|
-
if (typeof value !== 'number' || !isFinite(value)) {
|
72
|
-
throw new Error('Value must be a finite number');
|
73
|
-
}
|
74
|
-
|
75
|
-
const validValues = column.filter(val =>
|
76
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
77
|
-
);
|
78
|
-
|
79
|
-
if (validValues.length === 0) {
|
80
|
-
throw new Error('No valid numeric values found');
|
81
|
-
}
|
82
|
-
|
83
|
-
const countBelow = validValues.filter(val => val < value).length;
|
84
|
-
const countEqual = validValues.filter(val => val === value).length;
|
85
|
-
|
86
|
-
return ((countBelow + 0.5 * countEqual) / validValues.length) * 100;
|
87
|
-
}
|
88
|
-
|
89
|
-
zScore(column, value) {
|
90
|
-
if (!Array.isArray(column) || column.length === 0) {
|
91
|
-
throw new Error('Column must be a non-empty array');
|
92
|
-
}
|
93
|
-
|
94
|
-
if (typeof value !== 'number' || !isFinite(value)) {
|
95
|
-
throw new Error('Value must be a finite number');
|
96
|
-
}
|
97
|
-
|
98
|
-
const validValues = column.filter(val =>
|
99
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
100
|
-
);
|
101
|
-
|
102
|
-
if (validValues.length === 0) {
|
103
|
-
throw new Error('No valid numeric values found');
|
104
|
-
}
|
105
|
-
|
106
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / validValues.length;
|
107
|
-
const variance = validValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (validValues.length - 1);
|
108
|
-
const stdDev = Math.sqrt(variance);
|
109
|
-
|
110
|
-
if (stdDev === 0) {
|
111
|
-
throw new Error('Cannot calculate z-score when standard deviation is zero');
|
112
|
-
}
|
113
|
-
|
114
|
-
return (value - mean) / stdDev;
|
115
|
-
}
|
116
|
-
|
117
|
-
boxplotStats(column) {
|
118
|
-
const validValues = column.filter(val =>
|
119
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
120
|
-
);
|
121
|
-
|
122
|
-
if (validValues.length === 0) {
|
123
|
-
throw new Error('No valid numeric values found');
|
124
|
-
}
|
125
|
-
|
126
|
-
const sorted = validValues.sort((a, b) => a - b);
|
127
|
-
const q1 = this.quantile(sorted, 0.25);
|
128
|
-
const q2 = this.quantile(sorted, 0.5);
|
129
|
-
const q3 = this.quantile(sorted, 0.75);
|
130
|
-
const iqr = q3 - q1;
|
131
|
-
|
132
|
-
const lowerFence = q1 - 1.5 * iqr;
|
133
|
-
const upperFence = q3 + 1.5 * iqr;
|
134
|
-
|
135
|
-
const outliers = sorted.filter(val => val < lowerFence || val > upperFence);
|
136
|
-
const inliers = sorted.filter(val => val >= lowerFence && val <= upperFence);
|
137
|
-
|
138
|
-
return {
|
139
|
-
min: Math.min(...inliers),
|
140
|
-
q1: q1,
|
141
|
-
median: q2,
|
142
|
-
q3: q3,
|
143
|
-
max: Math.max(...inliers),
|
144
|
-
iqr: iqr,
|
145
|
-
lowerFence: lowerFence,
|
146
|
-
upperFence: upperFence,
|
147
|
-
outliers: outliers,
|
148
|
-
outlierCount: outliers.length
|
149
|
-
};
|
150
|
-
}
|
151
|
-
|
152
|
-
fiveNumberSummary(column) {
|
153
|
-
const validValues = column.filter(val =>
|
154
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
155
|
-
);
|
156
|
-
|
157
|
-
if (validValues.length === 0) {
|
158
|
-
throw new Error('No valid numeric values found');
|
159
|
-
}
|
160
|
-
|
161
|
-
return {
|
162
|
-
minimum: Math.min(...validValues),
|
163
|
-
q1: this.quantile(validValues, 0.25),
|
164
|
-
median: this.quantile(validValues, 0.5),
|
165
|
-
q3: this.quantile(validValues, 0.75),
|
166
|
-
maximum: Math.max(...validValues)
|
167
|
-
};
|
168
|
-
}
|
169
|
-
|
170
|
-
rank(column, method = 'average') {
|
171
|
-
if (!Array.isArray(column) || column.length === 0) {
|
172
|
-
throw new Error('Column must be a non-empty array');
|
173
|
-
}
|
174
|
-
|
175
|
-
const validIndices = [];
|
176
|
-
const validValues = [];
|
177
|
-
|
178
|
-
column.forEach((val, index) => {
|
179
|
-
if (typeof val === 'number' && !isNaN(val) && isFinite(val)) {
|
180
|
-
validIndices.push(index);
|
181
|
-
validValues.push({ value: val, originalIndex: index });
|
182
|
-
}
|
183
|
-
});
|
184
|
-
|
185
|
-
if (validValues.length === 0) {
|
186
|
-
throw new Error('No valid numeric values found');
|
187
|
-
}
|
188
|
-
|
189
|
-
validValues.sort((a, b) => a.value - b.value);
|
190
|
-
|
191
|
-
const ranks = new Array(column.length).fill(null);
|
192
|
-
|
193
|
-
let currentRank = 1;
|
194
|
-
for (let i = 0; i < validValues.length; i++) {
|
195
|
-
const currentValue = validValues[i].value;
|
196
|
-
const tiedIndices = [i];
|
197
|
-
|
198
|
-
while (i + 1 < validValues.length && validValues[i + 1].value === currentValue) {
|
199
|
-
i++;
|
200
|
-
tiedIndices.push(i);
|
201
|
-
}
|
202
|
-
|
203
|
-
let assignedRank;
|
204
|
-
switch (method) {
|
205
|
-
case 'average':
|
206
|
-
assignedRank = (currentRank + currentRank + tiedIndices.length - 1) / 2;
|
207
|
-
break;
|
208
|
-
case 'min':
|
209
|
-
assignedRank = currentRank;
|
210
|
-
break;
|
211
|
-
case 'max':
|
212
|
-
assignedRank = currentRank + tiedIndices.length - 1;
|
213
|
-
break;
|
214
|
-
case 'first':
|
215
|
-
tiedIndices.forEach((idx, pos) => {
|
216
|
-
ranks[validValues[idx].originalIndex] = currentRank + pos;
|
217
|
-
});
|
218
|
-
currentRank += tiedIndices.length;
|
219
|
-
continue;
|
220
|
-
default:
|
221
|
-
throw new Error('Unknown ranking method. Use: average, min, max, or first');
|
222
|
-
}
|
223
|
-
|
224
|
-
tiedIndices.forEach(idx => {
|
225
|
-
ranks[validValues[idx].originalIndex] = assignedRank;
|
226
|
-
});
|
227
|
-
|
228
|
-
currentRank += tiedIndices.length;
|
229
|
-
}
|
230
|
-
|
231
|
-
return ranks;
|
232
|
-
}
|
233
|
-
|
234
|
-
normalizedRank(column) {
|
235
|
-
const ranks = this.rank(column);
|
236
|
-
const validRanks = ranks.filter(rank => rank !== null);
|
237
|
-
const maxRank = Math.max(...validRanks);
|
238
|
-
|
239
|
-
return ranks.map(rank => rank !== null ? (rank - 1) / (maxRank - 1) : null);
|
240
|
-
}
|
241
|
-
|
242
|
-
standardizedValues(column) {
|
243
|
-
const validValues = column.filter(val =>
|
244
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
245
|
-
);
|
246
|
-
|
247
|
-
if (validValues.length === 0) {
|
248
|
-
throw new Error('No valid numeric values found');
|
249
|
-
}
|
250
|
-
|
251
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / validValues.length;
|
252
|
-
const variance = validValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (validValues.length - 1);
|
253
|
-
const stdDev = Math.sqrt(variance);
|
254
|
-
|
255
|
-
if (stdDev === 0) {
|
256
|
-
return column.map(val =>
|
257
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val) ? 0 : null
|
258
|
-
);
|
259
|
-
}
|
260
|
-
|
261
|
-
return column.map(val =>
|
262
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val) ?
|
263
|
-
(val - mean) / stdDev : null
|
264
|
-
);
|
265
|
-
}
|
266
|
-
}
|
267
|
-
|
268
|
-
export default Position;
|
package/src/descriptive/shape.js
DELETED
@@ -1,336 +0,0 @@
|
|
1
|
-
class Shape {
|
2
|
-
skewness(column, bias = true) {
|
3
|
-
if (!Array.isArray(column) || column.length === 0) {
|
4
|
-
throw new Error('Column must be a non-empty array');
|
5
|
-
}
|
6
|
-
|
7
|
-
const validValues = column.filter(val =>
|
8
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
9
|
-
);
|
10
|
-
|
11
|
-
if (validValues.length < 3) {
|
12
|
-
throw new Error('Skewness calculation requires at least 3 values');
|
13
|
-
}
|
14
|
-
|
15
|
-
const n = validValues.length;
|
16
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / n;
|
17
|
-
|
18
|
-
const variance = validValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
|
19
|
-
const stdDev = Math.sqrt(variance);
|
20
|
-
|
21
|
-
if (stdDev === 0) {
|
22
|
-
return 0;
|
23
|
-
}
|
24
|
-
|
25
|
-
const skewSum = validValues.reduce((sum, val) => {
|
26
|
-
return sum + Math.pow((val - mean) / stdDev, 3);
|
27
|
-
}, 0);
|
28
|
-
|
29
|
-
if (bias) {
|
30
|
-
return skewSum / n;
|
31
|
-
} else {
|
32
|
-
return (n / ((n - 1) * (n - 2))) * skewSum;
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
|
-
kurtosis(column, bias = true, fisher = true) {
|
37
|
-
if (!Array.isArray(column) || column.length === 0) {
|
38
|
-
throw new Error('Column must be a non-empty array');
|
39
|
-
}
|
40
|
-
|
41
|
-
const validValues = column.filter(val =>
|
42
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
43
|
-
);
|
44
|
-
|
45
|
-
if (validValues.length < 4) {
|
46
|
-
throw new Error('Kurtosis calculation requires at least 4 values');
|
47
|
-
}
|
48
|
-
|
49
|
-
const n = validValues.length;
|
50
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / n;
|
51
|
-
|
52
|
-
const variance = validValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (n - 1);
|
53
|
-
const stdDev = Math.sqrt(variance);
|
54
|
-
|
55
|
-
if (stdDev === 0) {
|
56
|
-
return fisher ? -3 : 0;
|
57
|
-
}
|
58
|
-
|
59
|
-
const kurtSum = validValues.reduce((sum, val) => {
|
60
|
-
return sum + Math.pow((val - mean) / stdDev, 4);
|
61
|
-
}, 0);
|
62
|
-
|
63
|
-
let kurtosis;
|
64
|
-
if (bias) {
|
65
|
-
kurtosis = kurtSum / n;
|
66
|
-
} else {
|
67
|
-
kurtosis = ((n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3))) * kurtSum -
|
68
|
-
(3 * Math.pow(n - 1, 2)) / ((n - 2) * (n - 3));
|
69
|
-
}
|
70
|
-
|
71
|
-
return fisher ? kurtosis - 3 : kurtosis;
|
72
|
-
}
|
73
|
-
|
74
|
-
isNormalDistribution(column, alpha = 0.05) {
|
75
|
-
const shapiroResult = this.shapiroWilkTest(column);
|
76
|
-
const jarqueBeraResult = this.jarqueBeraTest(column);
|
77
|
-
|
78
|
-
return {
|
79
|
-
shapiroWilk: {
|
80
|
-
statistic: shapiroResult.statistic,
|
81
|
-
pValue: shapiroResult.pValue,
|
82
|
-
isNormal: shapiroResult.pValue > alpha
|
83
|
-
},
|
84
|
-
jarqueBera: {
|
85
|
-
statistic: jarqueBeraResult.statistic,
|
86
|
-
pValue: jarqueBeraResult.pValue,
|
87
|
-
isNormal: jarqueBeraResult.pValue > alpha
|
88
|
-
},
|
89
|
-
skewness: this.skewness(column, false),
|
90
|
-
kurtosis: this.kurtosis(column, false, true),
|
91
|
-
isNormalByTests: shapiroResult.pValue > alpha && jarqueBeraResult.pValue > alpha
|
92
|
-
};
|
93
|
-
}
|
94
|
-
|
95
|
-
shapiroWilkTest(column) {
|
96
|
-
const validValues = column.filter(val =>
|
97
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
98
|
-
);
|
99
|
-
|
100
|
-
if (validValues.length < 3 || validValues.length > 5000) {
|
101
|
-
throw new Error('Shapiro-Wilk test requires between 3 and 5000 observations');
|
102
|
-
}
|
103
|
-
|
104
|
-
const n = validValues.length;
|
105
|
-
const sorted = [...validValues].sort((a, b) => a - b);
|
106
|
-
|
107
|
-
const mean = sorted.reduce((sum, val) => sum + val, 0) / n;
|
108
|
-
const ss = sorted.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0);
|
109
|
-
|
110
|
-
let b = 0;
|
111
|
-
for (let i = 0; i < Math.floor(n / 2); i++) {
|
112
|
-
const a = this.shapiroWilkCoefficient(i + 1, n);
|
113
|
-
b += a * (sorted[n - 1 - i] - sorted[i]);
|
114
|
-
}
|
115
|
-
|
116
|
-
const w = (b * b) / ss;
|
117
|
-
const pValue = this.shapiroWilkPValue(w, n);
|
118
|
-
|
119
|
-
return {
|
120
|
-
statistic: w,
|
121
|
-
pValue: pValue,
|
122
|
-
isNormal: pValue > 0.05
|
123
|
-
};
|
124
|
-
}
|
125
|
-
|
126
|
-
shapiroWilkCoefficient(i, n) {
|
127
|
-
const c = [
|
128
|
-
0, 0.7071, 0.7071, 0.6872, 0.6646, 0.6431, 0.6233, 0.6052, 0.5888, 0.5739, 0.5601
|
129
|
-
];
|
130
|
-
|
131
|
-
if (n <= 10 && i <= n) {
|
132
|
-
return c[i] || 0.5;
|
133
|
-
}
|
134
|
-
|
135
|
-
const m = 0.5;
|
136
|
-
const s = 1;
|
137
|
-
return m + s * this.normalInverse((i - 0.375) / (n + 0.25));
|
138
|
-
}
|
139
|
-
|
140
|
-
normalInverse(p) {
|
141
|
-
if (p <= 0 || p >= 1) {
|
142
|
-
throw new Error('p must be between 0 and 1');
|
143
|
-
}
|
144
|
-
|
145
|
-
const a0 = -3.969683028665376e+01;
|
146
|
-
const a1 = 2.209460984245205e+02;
|
147
|
-
const a2 = -2.759285104469687e+02;
|
148
|
-
const a3 = 1.383577518672690e+02;
|
149
|
-
const a4 = -3.066479806614716e+01;
|
150
|
-
const a5 = 2.506628277459239e+00;
|
151
|
-
|
152
|
-
const b1 = -5.447609879822406e+01;
|
153
|
-
const b2 = 1.615858368580409e+02;
|
154
|
-
const b3 = -1.556989798598866e+02;
|
155
|
-
const b4 = 6.680131188771972e+01;
|
156
|
-
const b5 = -1.328068155288572e+01;
|
157
|
-
|
158
|
-
if (p > 0.5) {
|
159
|
-
return -this.normalInverse(1 - p);
|
160
|
-
}
|
161
|
-
|
162
|
-
const q = Math.sqrt(-2 * Math.log(p));
|
163
|
-
return (((((a5 * q + a4) * q + a3) * q + a2) * q + a1) * q + a0) /
|
164
|
-
((((b5 * q + b4) * q + b3) * q + b2) * q + b1) * q + 1;
|
165
|
-
}
|
166
|
-
|
167
|
-
shapiroWilkPValue(w, n) {
|
168
|
-
if (n < 3) return 1;
|
169
|
-
if (w >= 1) return 1;
|
170
|
-
if (w <= 0) return 0;
|
171
|
-
|
172
|
-
const ln_w = Math.log(w);
|
173
|
-
let z;
|
174
|
-
|
175
|
-
if (n <= 11) {
|
176
|
-
const gamma = 0.459 * n - 2.273;
|
177
|
-
z = -gamma * ln_w;
|
178
|
-
} else {
|
179
|
-
const mu = -1.5861 - 0.31082 * Math.log(n) - 0.083751 * Math.log(n) ** 2 + 0.0038915 * Math.log(n) ** 3;
|
180
|
-
const sigma = Math.exp(-0.4803 - 0.082676 * Math.log(n) + 0.0030302 * Math.log(n) ** 2);
|
181
|
-
z = (ln_w - mu) / sigma;
|
182
|
-
}
|
183
|
-
|
184
|
-
return 1 - this.standardNormalCDF(z);
|
185
|
-
}
|
186
|
-
|
187
|
-
jarqueBeraTest(column) {
|
188
|
-
const validValues = column.filter(val =>
|
189
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
190
|
-
);
|
191
|
-
|
192
|
-
if (validValues.length < 4) {
|
193
|
-
throw new Error('Jarque-Bera test requires at least 4 observations');
|
194
|
-
}
|
195
|
-
|
196
|
-
const n = validValues.length;
|
197
|
-
const skew = this.skewness(column, false);
|
198
|
-
const kurt = this.kurtosis(column, false, true);
|
199
|
-
|
200
|
-
const jb = (n / 6) * (Math.pow(skew, 2) + Math.pow(kurt, 2) / 4);
|
201
|
-
const pValue = 1 - this.chiSquareCDF(jb, 2);
|
202
|
-
|
203
|
-
return {
|
204
|
-
statistic: jb,
|
205
|
-
pValue: pValue,
|
206
|
-
skewness: skew,
|
207
|
-
kurtosis: kurt,
|
208
|
-
isNormal: pValue > 0.05
|
209
|
-
};
|
210
|
-
}
|
211
|
-
|
212
|
-
standardNormalCDF(z) {
|
213
|
-
return 0.5 * (1 + this.erf(z / Math.sqrt(2)));
|
214
|
-
}
|
215
|
-
|
216
|
-
erf(x) {
|
217
|
-
const a1 = 0.254829592;
|
218
|
-
const a2 = -0.284496736;
|
219
|
-
const a3 = 1.421413741;
|
220
|
-
const a4 = -1.453152027;
|
221
|
-
const a5 = 1.061405429;
|
222
|
-
const p = 0.3275911;
|
223
|
-
|
224
|
-
const sign = x < 0 ? -1 : 1;
|
225
|
-
x = Math.abs(x);
|
226
|
-
|
227
|
-
const t = 1.0 / (1.0 + p * x);
|
228
|
-
const y = 1.0 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
|
229
|
-
|
230
|
-
return sign * y;
|
231
|
-
}
|
232
|
-
|
233
|
-
chiSquareCDF(x, df) {
|
234
|
-
if (x <= 0) return 0;
|
235
|
-
|
236
|
-
return this.incompleteGamma(df / 2, x / 2) / this.gamma(df / 2);
|
237
|
-
}
|
238
|
-
|
239
|
-
incompleteGamma(a, x) {
|
240
|
-
if (x <= 0) return 0;
|
241
|
-
if (a <= 0) return 1;
|
242
|
-
|
243
|
-
let sum = 1;
|
244
|
-
let term = 1;
|
245
|
-
|
246
|
-
for (let n = 1; n < 100; n++) {
|
247
|
-
term *= x / (a + n - 1);
|
248
|
-
sum += term;
|
249
|
-
if (Math.abs(term) < 1e-12) break;
|
250
|
-
}
|
251
|
-
|
252
|
-
return Math.pow(x, a) * Math.exp(-x) * sum;
|
253
|
-
}
|
254
|
-
|
255
|
-
gamma(x) {
|
256
|
-
if (x < 0.5) {
|
257
|
-
return Math.PI / (Math.sin(Math.PI * x) * this.gamma(1 - x));
|
258
|
-
}
|
259
|
-
|
260
|
-
x -= 1;
|
261
|
-
let result = 1;
|
262
|
-
const coefficients = [
|
263
|
-
0.99999999999980993, 676.5203681218851, -1259.1392167224028,
|
264
|
-
771.32342877765313, -176.61502916214059, 12.507343278686905,
|
265
|
-
-0.13857109526572012, 9.9843695780195716e-6, 1.5056327351493116e-7
|
266
|
-
];
|
267
|
-
|
268
|
-
result = coefficients[0];
|
269
|
-
for (let i = 1; i < coefficients.length; i++) {
|
270
|
-
result += coefficients[i] / (x + i);
|
271
|
-
}
|
272
|
-
|
273
|
-
const t = x + coefficients.length - 1.5;
|
274
|
-
return Math.sqrt(2 * Math.PI) * Math.pow(t, x + 0.5) * Math.exp(-t) * result;
|
275
|
-
}
|
276
|
-
|
277
|
-
momentCoefficient(column, moment) {
|
278
|
-
if (typeof moment !== 'number' || moment < 1) {
|
279
|
-
throw new Error('Moment must be a positive integer');
|
280
|
-
}
|
281
|
-
|
282
|
-
const validValues = column.filter(val =>
|
283
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
284
|
-
);
|
285
|
-
|
286
|
-
if (validValues.length === 0) {
|
287
|
-
throw new Error('No valid numeric values found');
|
288
|
-
}
|
289
|
-
|
290
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / validValues.length;
|
291
|
-
const momentSum = validValues.reduce((sum, val) => sum + Math.pow(val - mean, moment), 0);
|
292
|
-
|
293
|
-
return momentSum / validValues.length;
|
294
|
-
}
|
295
|
-
|
296
|
-
pearsonSkewness(column, mode = 1) {
|
297
|
-
const validValues = column.filter(val =>
|
298
|
-
typeof val === 'number' && !isNaN(val) && isFinite(val)
|
299
|
-
);
|
300
|
-
|
301
|
-
if (validValues.length === 0) {
|
302
|
-
throw new Error('No valid numeric values found');
|
303
|
-
}
|
304
|
-
|
305
|
-
const mean = validValues.reduce((sum, val) => sum + val, 0) / validValues.length;
|
306
|
-
const variance = validValues.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (validValues.length - 1);
|
307
|
-
const stdDev = Math.sqrt(variance);
|
308
|
-
|
309
|
-
if (stdDev === 0) {
|
310
|
-
return 0;
|
311
|
-
}
|
312
|
-
|
313
|
-
if (mode === 1) {
|
314
|
-
const sorted = [...validValues].sort((a, b) => a - b);
|
315
|
-
const median = sorted.length % 2 === 0 ?
|
316
|
-
(sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 :
|
317
|
-
sorted[Math.floor(sorted.length / 2)];
|
318
|
-
|
319
|
-
return (mean - median) / stdDev;
|
320
|
-
} else if (mode === 2) {
|
321
|
-
return 3 * (mean - this.median(validValues)) / stdDev;
|
322
|
-
} else {
|
323
|
-
throw new Error('Mode must be 1 or 2');
|
324
|
-
}
|
325
|
-
}
|
326
|
-
|
327
|
-
median(arr) {
|
328
|
-
const sorted = [...arr].sort((a, b) => a - b);
|
329
|
-
const mid = Math.floor(sorted.length / 2);
|
330
|
-
return sorted.length % 2 === 0 ?
|
331
|
-
(sorted[mid - 1] + sorted[mid]) / 2 :
|
332
|
-
sorted[mid];
|
333
|
-
}
|
334
|
-
}
|
335
|
-
|
336
|
-
export default Shape;
|