datly 0.0.1 → 0.0.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.
@@ -0,0 +1,543 @@
1
+ class Interpreter {
2
+ interpret(testResult) {
3
+ if (!testResult || typeof testResult !== 'object') {
4
+ throw new Error('Invalid test result object');
5
+ }
6
+
7
+ const testType = this.identifyTestType(testResult);
8
+
9
+ return {
10
+ testType: testType,
11
+ summary: this.generateSummary(testResult, testType),
12
+ conclusion: this.generateConclusion(testResult, testType),
13
+ significance: this.interpretSignificance(testResult),
14
+ effectSize: this.interpretEffectSize(testResult, testType),
15
+ confidence: this.assessConfidence(testResult),
16
+ assumptions: this.checkAssumptions(testType),
17
+ recommendations: this.generateRecommendations(testResult, testType),
18
+ plainLanguage: this.generatePlainLanguageSummary(testResult, testType)
19
+ };
20
+ }
21
+
22
+ identifyTestType(testResult) {
23
+ if (testResult.type) return testResult.type;
24
+
25
+ if (testResult.correlation !== undefined) return 'correlation';
26
+ if (testResult.rSquared !== undefined) return 'regression';
27
+ if (testResult.fStatistic !== undefined) return 'anova';
28
+ if (testResult.tStatistic !== undefined || testResult.statistic !== undefined) {
29
+ if (testResult.degreesOfFreedom !== undefined) return 't-test';
30
+ return 'z-test';
31
+ }
32
+ if (testResult.isNormal !== undefined) return 'normality-test';
33
+ if (testResult.clusters !== undefined) return 'clustering';
34
+
35
+ return 'general-test';
36
+ }
37
+
38
+ generateSummary(testResult, testType) {
39
+ switch (testType) {
40
+ case 'correlation':
41
+ return this.summarizeCorrelation(testResult);
42
+ case 'regression':
43
+ return this.summarizeRegression(testResult);
44
+ case 't-test':
45
+ return this.summarizeTTest(testResult);
46
+ case 'z-test':
47
+ return this.summarizeZTest(testResult);
48
+ case 'anova':
49
+ return this.summarizeANOVA(testResult);
50
+ case 'normality-test':
51
+ return this.summarizeNormalityTest(testResult);
52
+ default:
53
+ return this.summarizeGeneral(testResult);
54
+ }
55
+ }
56
+
57
+ summarizeCorrelation(testResult) {
58
+ const r = testResult.correlation;
59
+ const strength = this.getCorrelationStrength(Math.abs(r));
60
+ const direction = r > 0 ? 'positive' : 'negative';
61
+ const significance = testResult.pValue < 0.05 ? 'significant' : 'not significant';
62
+
63
+ return `${strength} ${direction} correlation (r = ${r.toFixed(3)}) that is ${significance}`;
64
+ }
65
+
66
+ summarizeRegression(testResult) {
67
+ const r2 = testResult.rSquared;
68
+ const variance = (r2 * 100).toFixed(1);
69
+ const significance = testResult.pValueModel < 0.05 ? 'significant' : 'not significant';
70
+
71
+ return `${significance} regression model explaining ${variance}% of variance (R² = ${r2.toFixed(3)})`;
72
+ }
73
+
74
+ summarizeTTest(testResult) {
75
+ const significance = testResult.pValue < 0.05 ? 'significant' : 'not significant';
76
+ const t = testResult.statistic || testResult.tStatistic;
77
+
78
+ return `${significance} difference between groups (t = ${t.toFixed(3)}, p = ${testResult.pValue.toFixed(4)})`;
79
+ }
80
+
81
+ summarizeZTest(testResult) {
82
+ const significance = testResult.pValue < 0.05 ? 'significant' : 'not significant';
83
+ const z = testResult.statistic || testResult.zStatistic;
84
+
85
+ return `${significance} result compared to population (z = ${z.toFixed(3)}, p = ${testResult.pValue.toFixed(4)})`;
86
+ }
87
+
88
+ summarizeANOVA(testResult) {
89
+ const significance = testResult.pValueModel < 0.05 ? 'significant' : 'not significant';
90
+ const f = testResult.fStatistic;
91
+
92
+ return `${significance} differences between groups (F = ${f.toFixed(3)}, p = ${testResult.pValueModel.toFixed(4)})`;
93
+ }
94
+
95
+ summarizeNormalityTest(testResult) {
96
+ const conclusion = testResult.isNormal ? 'normally distributed' : 'not normally distributed';
97
+ const testName = testResult.test || 'normality test';
98
+
99
+ return `Data appears ${conclusion} (${testName}, p = ${testResult.pValue?.toFixed(4) || 'N/A'})`;
100
+ }
101
+
102
+ summarizeGeneral(testResult) {
103
+ if (testResult.pValue !== undefined) {
104
+ const significance = testResult.pValue < 0.05 ? 'significant' : 'not significant';
105
+ return `${significance} statistical result (p = ${testResult.pValue.toFixed(4)})`;
106
+ }
107
+
108
+ return 'Statistical analysis completed';
109
+ }
110
+
111
+ generateConclusion(testResult, testType) {
112
+ const alpha = testResult.alpha || 0.05;
113
+ const pValue = testResult.pValue || testResult.pValueModel;
114
+
115
+ if (pValue === undefined) {
116
+ return {
117
+ decision: 'inconclusive',
118
+ statement: 'Cannot determine statistical significance - p-value unavailable'
119
+ };
120
+ }
121
+
122
+ const rejectNull = pValue < alpha;
123
+ const confidenceLevel = ((1 - alpha) * 100).toFixed(0);
124
+
125
+ let statement = '';
126
+ if (rejectNull) {
127
+ statement = `At the ${confidenceLevel}% confidence level, we reject the null hypothesis (p = ${pValue.toFixed(4)} < ${alpha}).`;
128
+ } else {
129
+ statement = `At the ${confidenceLevel}% confidence level, we fail to reject the null hypothesis (p = ${pValue.toFixed(4)} ≥ ${alpha}).`;
130
+ }
131
+
132
+ return {
133
+ decision: rejectNull ? 'reject_null' : 'fail_to_reject_null',
134
+ statement: statement,
135
+ alpha: alpha,
136
+ pValue: pValue,
137
+ confidenceLevel: parseInt(confidenceLevel)
138
+ };
139
+ }
140
+
141
+ interpretSignificance(testResult) {
142
+ const pValue = testResult.pValue || testResult.pValueModel;
143
+
144
+ if (pValue === undefined) {
145
+ return {
146
+ level: 'unknown',
147
+ interpretation: 'P-value not available'
148
+ };
149
+ }
150
+
151
+ let level, interpretation;
152
+
153
+ if (pValue < 0.001) {
154
+ level = 'very_strong';
155
+ interpretation = 'Very strong evidence against null hypothesis';
156
+ } else if (pValue < 0.01) {
157
+ level = 'strong';
158
+ interpretation = 'Strong evidence against null hypothesis';
159
+ } else if (pValue < 0.05) {
160
+ level = 'moderate';
161
+ interpretation = 'Moderate evidence against null hypothesis';
162
+ } else if (pValue < 0.1) {
163
+ level = 'weak';
164
+ interpretation = 'Weak evidence against null hypothesis';
165
+ } else {
166
+ level = 'none';
167
+ interpretation = 'No evidence against null hypothesis';
168
+ }
169
+
170
+ return {
171
+ level: level,
172
+ pValue: pValue,
173
+ interpretation: interpretation,
174
+ isSignificant: pValue < 0.05
175
+ };
176
+ }
177
+
178
+ interpretEffectSize(testResult, testType) {
179
+ switch (testType) {
180
+ case 'correlation':
181
+ return this.interpretCorrelationEffect(testResult);
182
+ case 'regression':
183
+ return this.interpretRegressionEffect(testResult);
184
+ case 't-test':
185
+ return this.interpretTTestEffect(testResult);
186
+ case 'anova':
187
+ return this.interpretANOVAEffect(testResult);
188
+ default:
189
+ return { interpretation: 'Effect size not available for this test type' };
190
+ }
191
+ }
192
+
193
+ interpretCorrelationEffect(testResult) {
194
+ const r = Math.abs(testResult.correlation);
195
+ const rSquared = r * r;
196
+
197
+ return {
198
+ value: r,
199
+ magnitude: this.getCorrelationStrength(r),
200
+ varianceExplained: (rSquared * 100).toFixed(1) + '%',
201
+ interpretation: `${this.getCorrelationStrength(r).toLowerCase()} relationship`,
202
+ cohen: this.getCohenCorrelation(r)
203
+ };
204
+ }
205
+
206
+ interpretRegressionEffect(testResult) {
207
+ const r2 = testResult.rSquared;
208
+
209
+ return {
210
+ value: r2,
211
+ magnitude: this.getRSquaredMagnitude(r2),
212
+ varianceExplained: (r2 * 100).toFixed(1) + '%',
213
+ interpretation: `${this.getRSquaredMagnitude(r2).toLowerCase()} explanatory power`
214
+ };
215
+ }
216
+
217
+ interpretTTestEffect(testResult) {
218
+ if (testResult.sample1Mean !== undefined && testResult.sample2Mean !== undefined) {
219
+ const diff = Math.abs(testResult.sample1Mean - testResult.sample2Mean);
220
+ const pooledStd = testResult.standardError * Math.sqrt(2);
221
+ const cohensD = diff / pooledStd;
222
+
223
+ return {
224
+ value: cohensD,
225
+ magnitude: this.getCohenD(cohensD),
226
+ interpretation: `${this.getCohenD(cohensD).toLowerCase()} effect size`,
227
+ meanDifference: diff
228
+ };
229
+ }
230
+
231
+ return { interpretation: 'Effect size cannot be calculated - insufficient data' };
232
+ }
233
+
234
+ interpretANOVAEffect(testResult) {
235
+ if (testResult.sumOfSquaresBetween && testResult.sumOfSquaresWithin) {
236
+ const etaSquared = testResult.sumOfSquaresBetween /
237
+ (testResult.sumOfSquaresBetween + testResult.sumOfSquaresWithin);
238
+
239
+ return {
240
+ value: etaSquared,
241
+ magnitude: this.getEtaSquared(etaSquared),
242
+ varianceExplained: (etaSquared * 100).toFixed(1) + '%',
243
+ interpretation: `${this.getEtaSquared(etaSquared).toLowerCase()} effect size`
244
+ };
245
+ }
246
+
247
+ return { interpretation: 'Effect size cannot be calculated - insufficient data' };
248
+ }
249
+
250
+ assessConfidence(testResult) {
251
+ const factors = [];
252
+ let confidence = 'medium';
253
+
254
+ if (testResult.sampleSize) {
255
+ if (testResult.sampleSize > 100) {
256
+ factors.push('Large sample size increases reliability');
257
+ confidence = 'high';
258
+ } else if (testResult.sampleSize < 30) {
259
+ factors.push('Small sample size may limit reliability');
260
+ confidence = 'low';
261
+ }
262
+ }
263
+
264
+ const pValue = testResult.pValue || testResult.pValueModel;
265
+ if (pValue !== undefined) {
266
+ if (pValue < 0.001) {
267
+ factors.push('Very low p-value strengthens confidence');
268
+ confidence = confidence === 'low' ? 'medium' : 'high';
269
+ } else if (pValue > 0.1) {
270
+ factors.push('High p-value suggests weak evidence');
271
+ confidence = 'low';
272
+ }
273
+ }
274
+
275
+ if (testResult.confidenceInterval) {
276
+ const ci = testResult.confidenceInterval;
277
+ const width = Math.abs(ci.upper - ci.lower);
278
+ const estimate = Math.abs((ci.upper + ci.lower) / 2);
279
+
280
+ if (estimate > 0 && width / estimate < 0.2) {
281
+ factors.push('Narrow confidence interval indicates precision');
282
+ } else {
283
+ factors.push('Wide confidence interval indicates uncertainty');
284
+ confidence = confidence === 'high' ? 'medium' : 'low';
285
+ }
286
+ }
287
+
288
+ return {
289
+ level: confidence,
290
+ factors: factors,
291
+ recommendation: this.getConfidenceRecommendation(confidence)
292
+ };
293
+ }
294
+
295
+ checkAssumptions(testType) {
296
+ const assumptions = [];
297
+
298
+ switch (testType) {
299
+ case 't-test':
300
+ assumptions.push(
301
+ 'Normality: Data should be approximately normally distributed',
302
+ 'Independence: Observations should be independent',
303
+ 'Equal variances: Groups should have similar variances (for independent samples)'
304
+ );
305
+ break;
306
+ case 'anova':
307
+ assumptions.push(
308
+ 'Normality: Residuals should be normally distributed',
309
+ 'Homogeneity: Groups should have equal variances',
310
+ 'Independence: Observations should be independent'
311
+ );
312
+ break;
313
+ case 'correlation':
314
+ assumptions.push(
315
+ 'Linearity: Relationship should be linear',
316
+ 'Normality: Variables should be approximately normal',
317
+ 'Homoscedasticity: Constant variance across range'
318
+ );
319
+ break;
320
+ case 'regression':
321
+ assumptions.push(
322
+ 'Linearity: Linear relationship between variables',
323
+ 'Independence: Residuals should be independent',
324
+ 'Homoscedasticity: Constant variance of residuals',
325
+ 'Normality: Residuals should be normally distributed'
326
+ );
327
+ break;
328
+ default:
329
+ assumptions.push('Check test-specific assumptions in documentation');
330
+ }
331
+
332
+ return {
333
+ testType: testType,
334
+ assumptions: assumptions,
335
+ importance: 'Violating assumptions may invalidate results'
336
+ };
337
+ }
338
+
339
+ generateRecommendations(testResult, testType) {
340
+ const recommendations = [];
341
+ const pValue = testResult.pValue || testResult.pValueModel;
342
+
343
+ if (pValue !== undefined) {
344
+ if (pValue < 0.001) {
345
+ recommendations.push('Very strong result - investigate practical significance and effect size');
346
+ } else if (pValue >= 0.05 && pValue < 0.1) {
347
+ recommendations.push('Marginally significant - consider collecting more data or using different approach');
348
+ } else if (pValue >= 0.1) {
349
+ recommendations.push('No significant effect found - examine data quality and consider alternative hypotheses');
350
+ }
351
+ }
352
+
353
+ if (testType === 'correlation' && testResult.sampleSize && testResult.sampleSize < 30) {
354
+ recommendations.push('Small sample size - correlation may not be reliable');
355
+ }
356
+
357
+ if (testType === 'regression' && testResult.rSquared < 0.3) {
358
+ recommendations.push('Low R² - consider additional predictors or different model');
359
+ }
360
+
361
+ if (testResult.assumptions && testResult.assumptions.violated) {
362
+ recommendations.push('Assumptions may be violated - consider alternative tests or data transformations');
363
+ }
364
+
365
+ recommendations.push('Replicate findings with independent data when possible');
366
+
367
+ return recommendations;
368
+ }
369
+
370
+ generatePlainLanguageSummary(testResult, testType) {
371
+ const pValue = testResult.pValue || testResult.pValueModel;
372
+ const isSignificant = pValue && pValue < 0.05;
373
+
374
+ let summary = '';
375
+
376
+ if (isSignificant) {
377
+ summary += '✓ SIGNIFICANT RESULT: ';
378
+ } else {
379
+ summary += '✗ NOT SIGNIFICANT: ';
380
+ }
381
+
382
+ switch (testType) {
383
+ case 'correlation':
384
+ const r = testResult.correlation;
385
+ const strength = this.getCorrelationStrength(Math.abs(r));
386
+ if (isSignificant) {
387
+ summary += `Found a ${strength.toLowerCase()} ${r > 0 ? 'positive' : 'negative'} relationship between the variables.`;
388
+ } else {
389
+ summary += 'No meaningful relationship found between the variables.';
390
+ }
391
+ break;
392
+
393
+ case 'regression':
394
+ const variance = (testResult.rSquared * 100).toFixed(0);
395
+ if (isSignificant) {
396
+ summary += `The model successfully predicts the outcome, explaining ${variance}% of the variation.`;
397
+ } else {
398
+ summary += 'The model does not provide meaningful predictions.';
399
+ }
400
+ break;
401
+
402
+ case 't-test':
403
+ if (isSignificant) {
404
+ summary += 'Found a meaningful difference between the groups.';
405
+ } else {
406
+ summary += 'No meaningful difference found between the groups.';
407
+ }
408
+ break;
409
+
410
+ case 'anova':
411
+ if (isSignificant) {
412
+ summary += 'Found meaningful differences between at least some groups.';
413
+ } else {
414
+ summary += 'No meaningful differences found between groups.';
415
+ }
416
+ break;
417
+
418
+ case 'normality-test':
419
+ if (testResult.isNormal) {
420
+ summary += 'Data follows a normal distribution - suitable for standard statistical tests.';
421
+ } else {
422
+ summary += 'Data does not follow a normal distribution - consider alternative tests.';
423
+ }
424
+ break;
425
+
426
+ default:
427
+ if (isSignificant) {
428
+ summary += 'The statistical test shows a significant result.';
429
+ } else {
430
+ summary += 'The statistical test shows no significant result.';
431
+ }
432
+ }
433
+
434
+ if (pValue !== undefined) {
435
+ summary += ` (p-value: ${pValue.toFixed(4)})`;
436
+ }
437
+
438
+ return summary;
439
+ }
440
+
441
+ getCorrelationStrength(r) {
442
+ if (r >= 0.9) return 'Very Strong';
443
+ if (r >= 0.7) return 'Strong';
444
+ if (r >= 0.5) return 'Moderate';
445
+ if (r >= 0.3) return 'Weak';
446
+ return 'Very Weak';
447
+ }
448
+
449
+ getCohenCorrelation(r) {
450
+ if (r >= 0.5) return 'Large effect';
451
+ if (r >= 0.3) return 'Medium effect';
452
+ if (r >= 0.1) return 'Small effect';
453
+ return 'Negligible effect';
454
+ }
455
+
456
+ getRSquaredMagnitude(r2) {
457
+ if (r2 >= 0.7) return 'Strong';
458
+ if (r2 >= 0.5) return 'Moderate';
459
+ if (r2 >= 0.3) return 'Weak';
460
+ return 'Very Weak';
461
+ }
462
+
463
+ getCohenD(d) {
464
+ if (d >= 0.8) return 'Large';
465
+ if (d >= 0.5) return 'Medium';
466
+ if (d >= 0.2) return 'Small';
467
+ return 'Negligible';
468
+ }
469
+
470
+ getEtaSquared(eta2) {
471
+ if (eta2 >= 0.14) return 'Large';
472
+ if (eta2 >= 0.06) return 'Medium';
473
+ if (eta2 >= 0.01) return 'Small';
474
+ return 'Negligible';
475
+ }
476
+
477
+ getConfidenceRecommendation(confidence) {
478
+ switch (confidence) {
479
+ case 'high':
480
+ return 'Results appear robust and reliable';
481
+ case 'medium':
482
+ return 'Results are reasonably reliable but verify when possible';
483
+ case 'low':
484
+ return 'Interpret results with caution - consider additional validation';
485
+ default:
486
+ return 'Assess result reliability based on context';
487
+ }
488
+ }
489
+
490
+ formatForReport(interpretation) {
491
+ return {
492
+ title: `${interpretation.testType.toUpperCase()} Results`,
493
+ summary: interpretation.summary,
494
+ conclusion: interpretation.conclusion.statement,
495
+ significance: interpretation.significance.interpretation,
496
+ effect: interpretation.effectSize.interpretation,
497
+ confidence: interpretation.confidence.level,
498
+ recommendations: interpretation.recommendations,
499
+ plainLanguage: interpretation.plainLanguage
500
+ };
501
+ }
502
+
503
+ explainStatistic(testResult, testType) {
504
+ const explanations = {
505
+ 'correlation': 'Correlation measures the linear relationship between two variables, ranging from -1 to +1.',
506
+ 'regression': 'R² shows how much variance in the outcome is explained by the predictors.',
507
+ 't-test': 'T-test compares means between groups or against a known value.',
508
+ 'anova': 'ANOVA tests whether there are differences between multiple group means.',
509
+ 'z-test': 'Z-test compares a sample mean to a population mean when population variance is known.',
510
+ 'normality-test': 'Tests whether data follows a normal (bell-curve) distribution.'
511
+ };
512
+
513
+ return explanations[testType] || 'Statistical test to evaluate hypotheses about data.';
514
+ }
515
+
516
+ generateActionItems(interpretation) {
517
+ const actions = [];
518
+ const testType = interpretation.testType;
519
+ const isSignificant = interpretation.significance.isSignificant;
520
+
521
+ if (isSignificant) {
522
+ actions.push('Examine practical significance of the finding');
523
+ actions.push('Consider replicating with independent data');
524
+
525
+ if (testType === 'correlation') {
526
+ actions.push('Explore potential causal relationships');
527
+ }
528
+ if (testType === 'regression') {
529
+ actions.push('Validate model with new data');
530
+ }
531
+ } else {
532
+ actions.push('Review data collection methods');
533
+ actions.push('Consider if sample size was adequate');
534
+ actions.push('Explore alternative analytical approaches');
535
+ }
536
+
537
+ actions.push('Document methodology and assumptions');
538
+
539
+ return actions;
540
+ }
541
+ }
542
+
543
+ export default Interpreter;