-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathxyCumulativeDistributionStatistics.ts
More file actions
73 lines (63 loc) · 1.88 KB
/
xyCumulativeDistributionStatistics.ts
File metadata and controls
73 lines (63 loc) · 1.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import type { DataXY } from 'cheminfo-types';
import { xCumulative, xMaxValue } from '../x/index.ts';
import { xyCheck } from './xyCheck.ts';
import { xyMaxYPoint } from './xyMaxYPoint.ts';
const STEPS = [0.25, 0.5, 0.75] as const;
export interface XYCumulativeDistributionStatisticsResult {
x0: number;
x25: number;
x50: number;
x75: number;
x100: number;
xMode: number;
xMean: number;
}
/**
* Cumulative Distribution Statistics
* @param data - array of points {x,y}
* @returns x0, x25, x50, x75, x100, xMode, xMean (x for maxY)
*/
export function xyCumulativeDistributionStatistics(
data: DataXY,
): XYCumulativeDistributionStatisticsResult {
xyCheck(data, { minLength: 1 });
const { x, y } = data;
const cumulativeSum = xCumulative(y);
const maxY = xMaxValue(cumulativeSum);
for (let i = 0; i < cumulativeSum.length; i++) {
cumulativeSum[i] /= maxY;
}
const result: XYCumulativeDistributionStatisticsResult = {
x0: x[0],
x25: 0,
x50: 0,
x75: 0,
x100: x.at(-1) as number,
xMode: 0,
xMean: 0,
};
// need to find the x values closest to STEPS/100
let currentStep = 0;
breakPoint: for (let i = 1; i < cumulativeSum.length; i++) {
while (STEPS[currentStep] < cumulativeSum[i]) {
// Key is computed dynamically with a multiplication. This cannot be type-safe, hence the "as" assertion.
const key = `x${STEPS[currentStep] * 100}` as keyof typeof result;
result[key] =
x[i - 1] +
(x[i] - x[i - 1]) *
((STEPS[currentStep] - cumulativeSum[i - 1]) /
(cumulativeSum[i] - cumulativeSum[i - 1]));
currentStep++;
if (currentStep === STEPS.length) break breakPoint;
}
}
result.xMode = xyMaxYPoint(data).x;
let sumXY = 0;
let sumY = 0;
for (let i = 0; i < x.length; i++) {
sumXY += x[i] * y[i];
sumY += y[i];
}
result.xMean = sumXY / sumY;
return result;
}