@tangle-network/agent-eval 0.120.2 → 0.120.4
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/CHANGELOG.md +13 -0
- package/dist/analyst/index.d.ts +3111 -0
- package/dist/analyst/index.js +403 -0
- package/dist/analyst/index.js.map +1 -0
- package/dist/authenticity/index.d.ts +161 -0
- package/dist/authenticity/index.js +215 -0
- package/dist/authenticity/index.js.map +1 -0
- package/dist/belief-state/index.d.ts +1301 -0
- package/dist/belief-state/index.js +2152 -0
- package/dist/belief-state/index.js.map +1 -0
- package/dist/benchmarks/index.d.ts +974 -0
- package/dist/benchmarks/index.js +60 -0
- package/dist/benchmarks/index.js.map +1 -0
- package/dist/builder-eval/index.d.ts +695 -0
- package/dist/builder-eval/index.js +366 -0
- package/dist/builder-eval/index.js.map +1 -0
- package/dist/campaign/index.d.ts +7469 -0
- package/dist/campaign/index.js +272 -0
- package/dist/campaign/index.js.map +1 -0
- package/dist/chunk-3RF76KTD.js +84 -0
- package/dist/chunk-3RF76KTD.js.map +1 -0
- package/dist/chunk-3XH4Y2SS.js +750 -0
- package/dist/chunk-3XH4Y2SS.js.map +1 -0
- package/dist/chunk-3YYRZDON.js +45 -0
- package/dist/chunk-3YYRZDON.js.map +1 -0
- package/dist/chunk-5BYTIDZ7.js +550 -0
- package/dist/chunk-5BYTIDZ7.js.map +1 -0
- package/dist/chunk-5CVUPHJ4.js +2668 -0
- package/dist/chunk-5CVUPHJ4.js.map +1 -0
- package/dist/chunk-7QBFOJ3E.js +3920 -0
- package/dist/chunk-7QBFOJ3E.js.map +1 -0
- package/dist/chunk-ARU2PZFM.js +312 -0
- package/dist/chunk-ARU2PZFM.js.map +1 -0
- package/dist/chunk-BOD4O7OF.js +40 -0
- package/dist/chunk-BOD4O7OF.js.map +1 -0
- package/dist/chunk-CVJP5TMD.js +766 -0
- package/dist/chunk-CVJP5TMD.js.map +1 -0
- package/dist/chunk-DPZAEKA6.js +880 -0
- package/dist/chunk-DPZAEKA6.js.map +1 -0
- package/dist/chunk-DTJ6QUQB.js +131 -0
- package/dist/chunk-DTJ6QUQB.js.map +1 -0
- package/dist/chunk-GGE4NNQT.js +65 -0
- package/dist/chunk-GGE4NNQT.js.map +1 -0
- package/dist/chunk-H5UD2323.js +286 -0
- package/dist/chunk-H5UD2323.js.map +1 -0
- package/dist/chunk-HHWE3POT.js +94 -0
- package/dist/chunk-HHWE3POT.js.map +1 -0
- package/dist/chunk-HKUCJ437.js +787 -0
- package/dist/chunk-HKUCJ437.js.map +1 -0
- package/dist/chunk-JHCHEVET.js +274 -0
- package/dist/chunk-JHCHEVET.js.map +1 -0
- package/dist/chunk-K4DBDHLK.js +158 -0
- package/dist/chunk-K4DBDHLK.js.map +1 -0
- package/dist/chunk-K6N6XJJX.js +306 -0
- package/dist/chunk-K6N6XJJX.js.map +1 -0
- package/dist/chunk-MA6HLL3S.js +65 -0
- package/dist/chunk-MA6HLL3S.js.map +1 -0
- package/dist/chunk-MAZ26DC7.js +99 -0
- package/dist/chunk-MAZ26DC7.js.map +1 -0
- package/dist/chunk-MOXWMGPC.js +577 -0
- package/dist/chunk-MOXWMGPC.js.map +1 -0
- package/dist/chunk-NJC7U437.js +626 -0
- package/dist/chunk-NJC7U437.js.map +1 -0
- package/dist/chunk-NMN4WGSJ.js +1030 -0
- package/dist/chunk-NMN4WGSJ.js.map +1 -0
- package/dist/chunk-NPCTHQIO.js +91 -0
- package/dist/chunk-NPCTHQIO.js.map +1 -0
- package/dist/chunk-ONWEPEDO.js +57 -0
- package/dist/chunk-ONWEPEDO.js.map +1 -0
- package/dist/chunk-OYZAPX5G.js +1526 -0
- package/dist/chunk-OYZAPX5G.js.map +1 -0
- package/dist/chunk-PC4UYEBM.js +166 -0
- package/dist/chunk-PC4UYEBM.js.map +1 -0
- package/dist/chunk-PJQFMIOX.js +1182 -0
- package/dist/chunk-PJQFMIOX.js.map +1 -0
- package/dist/chunk-PXD6ZFNY.js +1107 -0
- package/dist/chunk-PXD6ZFNY.js.map +1 -0
- package/dist/chunk-PXE2VKMX.js +140 -0
- package/dist/chunk-PXE2VKMX.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-QBRSJK47.js +622 -0
- package/dist/chunk-QBRSJK47.js.map +1 -0
- package/dist/chunk-S3UZOQ5Y.js +328 -0
- package/dist/chunk-S3UZOQ5Y.js.map +1 -0
- package/dist/chunk-SQQED7ZH.js +998 -0
- package/dist/chunk-SQQED7ZH.js.map +1 -0
- package/dist/chunk-SYV364BL.js +1266 -0
- package/dist/chunk-SYV364BL.js.map +1 -0
- package/dist/chunk-T4SQEITX.js +95 -0
- package/dist/chunk-T4SQEITX.js.map +1 -0
- package/dist/chunk-TT4KNT67.js +124 -0
- package/dist/chunk-TT4KNT67.js.map +1 -0
- package/dist/chunk-U5CHZ5M3.js +357 -0
- package/dist/chunk-U5CHZ5M3.js.map +1 -0
- package/dist/chunk-ULOKLHIQ.js +1937 -0
- package/dist/chunk-ULOKLHIQ.js.map +1 -0
- package/dist/chunk-VI2UW6B6.js +162 -0
- package/dist/chunk-VI2UW6B6.js.map +1 -0
- package/dist/chunk-VQMK5FMP.js +247 -0
- package/dist/chunk-VQMK5FMP.js.map +1 -0
- package/dist/chunk-VSMTAMNK.js +53 -0
- package/dist/chunk-VSMTAMNK.js.map +1 -0
- package/dist/chunk-VZSRQ272.js +149 -0
- package/dist/chunk-VZSRQ272.js.map +1 -0
- package/dist/chunk-WW2A73HW.js +159 -0
- package/dist/chunk-WW2A73HW.js.map +1 -0
- package/dist/chunk-X4UCIOTZ.js +136 -0
- package/dist/chunk-X4UCIOTZ.js.map +1 -0
- package/dist/chunk-XJYR7XFV.js +317 -0
- package/dist/chunk-XJYR7XFV.js.map +1 -0
- package/dist/chunk-ZET2UAYW.js +89 -0
- package/dist/chunk-ZET2UAYW.js.map +1 -0
- package/dist/chunk-ZMXDQ4K7.js +870 -0
- package/dist/chunk-ZMXDQ4K7.js.map +1 -0
- package/dist/chunk-ZTJPIIVI.js +7958 -0
- package/dist/chunk-ZTJPIIVI.js.map +1 -0
- package/dist/chunk-ZZUXHH3R.js +99 -0
- package/dist/chunk-ZZUXHH3R.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +112 -0
- package/dist/cli.js.map +1 -0
- package/dist/contract/index.d.ts +4987 -0
- package/dist/contract/index.js +1654 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/control.d.ts +1013 -0
- package/dist/control.js +34 -0
- package/dist/control.js.map +1 -0
- package/dist/fuzz.d.ts +759 -0
- package/dist/fuzz.js +714 -0
- package/dist/fuzz.js.map +1 -0
- package/dist/hosted/index.d.ts +730 -0
- package/dist/hosted/index.js +14 -0
- package/dist/hosted/index.js.map +1 -0
- package/dist/index.d.ts +16780 -0
- package/dist/index.js +12168 -0
- package/dist/index.js.map +1 -0
- package/dist/matrix/index.d.ts +155 -0
- package/dist/matrix/index.js +8 -0
- package/dist/matrix/index.js.map +1 -0
- package/dist/meta-eval/index.d.ts +1030 -0
- package/dist/meta-eval/index.js +417 -0
- package/dist/meta-eval/index.js.map +1 -0
- package/dist/multishot/index.d.ts +579 -0
- package/dist/multishot/index.js +589 -0
- package/dist/multishot/index.js.map +1 -0
- package/dist/openapi.json +992 -0
- package/dist/pipelines/index.d.ts +567 -0
- package/dist/pipelines/index.js +515 -0
- package/dist/pipelines/index.js.map +1 -0
- package/dist/reporting.d.ts +1277 -0
- package/dist/reporting.js +48 -0
- package/dist/reporting.js.map +1 -0
- package/dist/rl.d.ts +4092 -0
- package/dist/rl.js +1724 -0
- package/dist/rl.js.map +1 -0
- package/dist/run-campaign-75RTPVV5.js +14 -0
- package/dist/run-campaign-75RTPVV5.js.map +1 -0
- package/dist/storyboard/index.d.ts +279 -0
- package/dist/storyboard/index.js +767 -0
- package/dist/storyboard/index.js.map +1 -0
- package/dist/trace-attributes.d.ts +52 -0
- package/dist/trace-attributes.js +62 -0
- package/dist/trace-attributes.js.map +1 -0
- package/dist/traces.d.ts +2343 -0
- package/dist/traces.js +249 -0
- package/dist/traces.js.map +1 -0
- package/dist/wire/index.d.ts +1252 -0
- package/dist/wire/index.js +81 -0
- package/dist/wire/index.js.map +1 -0
- package/docs/eval-surface-map.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ValidationError
|
|
3
|
+
} from "./chunk-ONWEPEDO.js";
|
|
4
|
+
|
|
5
|
+
// src/statistics.ts
|
|
6
|
+
var normalizeScores = (scores) => scores;
|
|
7
|
+
function weightedMean(scores) {
|
|
8
|
+
if (scores.length === 0) return 0;
|
|
9
|
+
let totalWeight = 0;
|
|
10
|
+
let weightedSum = 0;
|
|
11
|
+
for (const { score, weight } of scores) {
|
|
12
|
+
const w = weight ?? 1;
|
|
13
|
+
weightedSum += score * w;
|
|
14
|
+
totalWeight += w;
|
|
15
|
+
}
|
|
16
|
+
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
17
|
+
}
|
|
18
|
+
function confidenceInterval(scores, confidence = 0.95, opts = {}) {
|
|
19
|
+
if (scores.length === 0) return { mean: 0, lower: 0, upper: 0 };
|
|
20
|
+
if (scores.length === 1) return { mean: scores[0], lower: scores[0], upper: scores[0] };
|
|
21
|
+
const n = scores.length;
|
|
22
|
+
const mean = scores.reduce((a, b) => a + b, 0) / n;
|
|
23
|
+
const B = opts.resamples ?? 1e3;
|
|
24
|
+
const rng = makeRng(opts.seed);
|
|
25
|
+
const bootstrapMeans = [];
|
|
26
|
+
for (let i = 0; i < B; i++) {
|
|
27
|
+
let sum = 0;
|
|
28
|
+
for (let j = 0; j < n; j++) {
|
|
29
|
+
sum += scores[Math.floor(rng() * n)];
|
|
30
|
+
}
|
|
31
|
+
bootstrapMeans.push(sum / n);
|
|
32
|
+
}
|
|
33
|
+
bootstrapMeans.sort((a, b) => a - b);
|
|
34
|
+
const alpha = 1 - confidence;
|
|
35
|
+
const lowerIdx = Math.floor(alpha / 2 * B);
|
|
36
|
+
const upperIdx = Math.floor((1 - alpha / 2) * B) - 1;
|
|
37
|
+
return {
|
|
38
|
+
mean,
|
|
39
|
+
lower: bootstrapMeans[lowerIdx],
|
|
40
|
+
upper: bootstrapMeans[Math.min(upperIdx, B - 1)]
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function interRaterReliability(judgeScores) {
|
|
44
|
+
if (judgeScores.length < 2) return 1;
|
|
45
|
+
const dimensionMap = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const judgeSet of judgeScores) {
|
|
47
|
+
for (const s of judgeSet) {
|
|
48
|
+
if (!dimensionMap.has(s.dimension)) dimensionMap.set(s.dimension, []);
|
|
49
|
+
const arr = dimensionMap.get(s.dimension);
|
|
50
|
+
if (arr.length === 0 || arr[arr.length - 1].length >= judgeScores.length) {
|
|
51
|
+
arr.push([s.score]);
|
|
52
|
+
} else {
|
|
53
|
+
arr[arr.length - 1].push(s.score);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const allValues = [];
|
|
58
|
+
const pairDiffs = [];
|
|
59
|
+
for (const items of dimensionMap.values()) {
|
|
60
|
+
for (const ratings of items) {
|
|
61
|
+
if (ratings.length < 2) continue;
|
|
62
|
+
for (const v of ratings) allValues.push(v);
|
|
63
|
+
for (let i = 0; i < ratings.length; i++) {
|
|
64
|
+
for (let j = i + 1; j < ratings.length; j++) {
|
|
65
|
+
pairDiffs.push((ratings[i] - ratings[j]) ** 2);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (pairDiffs.length === 0 || allValues.length < 2) return 1;
|
|
71
|
+
const observedDisagreement = pairDiffs.reduce((a, b) => a + b, 0) / pairDiffs.length;
|
|
72
|
+
let expectedDisagreement = 0;
|
|
73
|
+
let expectedCount = 0;
|
|
74
|
+
for (let i = 0; i < allValues.length; i++) {
|
|
75
|
+
for (let j = i + 1; j < allValues.length; j++) {
|
|
76
|
+
expectedDisagreement += (allValues[i] - allValues[j]) ** 2;
|
|
77
|
+
expectedCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
expectedDisagreement = expectedCount > 0 ? expectedDisagreement / expectedCount : 0;
|
|
81
|
+
if (expectedDisagreement === 0) return 1;
|
|
82
|
+
return 1 - observedDisagreement / expectedDisagreement;
|
|
83
|
+
}
|
|
84
|
+
function mannWhitneyU(a, b) {
|
|
85
|
+
if (a.length === 0 || b.length === 0) return { u: 0, p: 1 };
|
|
86
|
+
const n1 = a.length;
|
|
87
|
+
const n2 = b.length;
|
|
88
|
+
const combined = [
|
|
89
|
+
...a.map((v) => ({ v, group: "a" })),
|
|
90
|
+
...b.map((v) => ({ v, group: "b" }))
|
|
91
|
+
].sort((x, y) => x.v - y.v);
|
|
92
|
+
const ranks2 = new Array(combined.length);
|
|
93
|
+
let i = 0;
|
|
94
|
+
while (i < combined.length) {
|
|
95
|
+
let j = i;
|
|
96
|
+
while (j < combined.length && combined[j].v === combined[i].v) j++;
|
|
97
|
+
const avgRank = (i + 1 + j) / 2;
|
|
98
|
+
for (let k = i; k < j; k++) ranks2[k] = avgRank;
|
|
99
|
+
i = j;
|
|
100
|
+
}
|
|
101
|
+
let r1 = 0;
|
|
102
|
+
for (let k = 0; k < combined.length; k++) {
|
|
103
|
+
if (combined[k].group === "a") r1 += ranks2[k];
|
|
104
|
+
}
|
|
105
|
+
const u1 = r1 - n1 * (n1 + 1) / 2;
|
|
106
|
+
const u2 = n1 * n2 - u1;
|
|
107
|
+
const u = Math.min(u1, u2);
|
|
108
|
+
const mu = n1 * n2 / 2;
|
|
109
|
+
const sigma = Math.sqrt(n1 * n2 * (n1 + n2 + 1) / 12);
|
|
110
|
+
if (sigma === 0) return { u, p: 1 };
|
|
111
|
+
const z = Math.abs(u - mu) / sigma;
|
|
112
|
+
const p = 2 * (1 - normalCdf(z));
|
|
113
|
+
return { u, p };
|
|
114
|
+
}
|
|
115
|
+
function partialCredit(current, target) {
|
|
116
|
+
if (target <= 0) return 1;
|
|
117
|
+
return Math.min(1, Math.max(0, current / target));
|
|
118
|
+
}
|
|
119
|
+
function pairedTTest(before, after) {
|
|
120
|
+
if (before.length !== after.length) {
|
|
121
|
+
throw new ValidationError(
|
|
122
|
+
`pairedTTest: unequal sample sizes (${before.length} vs ${after.length})`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
const n = before.length;
|
|
126
|
+
if (n < 2) return { t: 0, df: 0, p: 1 };
|
|
127
|
+
const diffs = before.map((b, i) => after[i] - b);
|
|
128
|
+
const mean = diffs.reduce((a, b) => a + b, 0) / n;
|
|
129
|
+
const variance = diffs.reduce((acc, d) => acc + (d - mean) ** 2, 0) / (n - 1);
|
|
130
|
+
const se = Math.sqrt(variance / n);
|
|
131
|
+
if (se === 0) return { t: mean === 0 ? 0 : Infinity, df: n - 1, p: mean === 0 ? 1 : 0 };
|
|
132
|
+
const t = mean / se;
|
|
133
|
+
const df = n - 1;
|
|
134
|
+
const p = 2 * (1 - studentTCdf(Math.abs(t), df));
|
|
135
|
+
return { t, df, p };
|
|
136
|
+
}
|
|
137
|
+
function wilcoxonSignedRank(before, after) {
|
|
138
|
+
if (before.length !== after.length) {
|
|
139
|
+
throw new ValidationError(
|
|
140
|
+
`wilcoxonSignedRank: unequal sample sizes (${before.length} vs ${after.length})`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const diffs = before.map((b, i2) => after[i2] - b).filter((d) => d !== 0);
|
|
144
|
+
const n = diffs.length;
|
|
145
|
+
if (n < 6) return { w: 0, p: 1 };
|
|
146
|
+
const absRanks = diffs.map((d, i2) => ({ abs: Math.abs(d), sign: Math.sign(d), i: i2 })).sort((a, b) => a.abs - b.abs);
|
|
147
|
+
const ranks2 = new Array(n);
|
|
148
|
+
let i = 0;
|
|
149
|
+
while (i < n) {
|
|
150
|
+
let j = i;
|
|
151
|
+
while (j < n && absRanks[j].abs === absRanks[i].abs) j++;
|
|
152
|
+
const avg = (i + 1 + j) / 2;
|
|
153
|
+
for (let k = i; k < j; k++) ranks2[absRanks[k].i] = avg;
|
|
154
|
+
i = j;
|
|
155
|
+
}
|
|
156
|
+
let wPlus = 0;
|
|
157
|
+
for (let k = 0; k < n; k++) if (diffs[k] > 0) wPlus += ranks2[k];
|
|
158
|
+
const mean = n * (n + 1) / 4;
|
|
159
|
+
const variance = n * (n + 1) * (2 * n + 1) / 24;
|
|
160
|
+
const z = (wPlus - mean) / Math.sqrt(variance);
|
|
161
|
+
const p = 2 * (1 - normalCdf(Math.abs(z)));
|
|
162
|
+
return { w: wPlus, p };
|
|
163
|
+
}
|
|
164
|
+
function cohensD(a, b) {
|
|
165
|
+
if (a.length < 2 || b.length < 2) return 0;
|
|
166
|
+
const meanA = a.reduce((x, y) => x + y, 0) / a.length;
|
|
167
|
+
const meanB = b.reduce((x, y) => x + y, 0) / b.length;
|
|
168
|
+
const varA = a.reduce((acc, x) => acc + (x - meanA) ** 2, 0) / (a.length - 1);
|
|
169
|
+
const varB = b.reduce((acc, x) => acc + (x - meanB) ** 2, 0) / (b.length - 1);
|
|
170
|
+
const pooled = Math.sqrt(
|
|
171
|
+
((a.length - 1) * varA + (b.length - 1) * varB) / (a.length + b.length - 2)
|
|
172
|
+
);
|
|
173
|
+
if (pooled === 0) return 0;
|
|
174
|
+
return (meanB - meanA) / pooled;
|
|
175
|
+
}
|
|
176
|
+
function cliffsDelta(before, after) {
|
|
177
|
+
const n = before.length * after.length;
|
|
178
|
+
if (n === 0) return 0;
|
|
179
|
+
let dominance = 0;
|
|
180
|
+
for (const a of after) {
|
|
181
|
+
for (const b of before) {
|
|
182
|
+
if (a > b) dominance += 1;
|
|
183
|
+
else if (a < b) dominance -= 1;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return dominance / n;
|
|
187
|
+
}
|
|
188
|
+
function interpretCliffs(delta) {
|
|
189
|
+
const d = Math.abs(delta);
|
|
190
|
+
if (d < 0.147) return "negligible";
|
|
191
|
+
if (d < 0.33) return "small";
|
|
192
|
+
if (d < 0.474) return "medium";
|
|
193
|
+
return "large";
|
|
194
|
+
}
|
|
195
|
+
function ranks(xs) {
|
|
196
|
+
const indexed = xs.map((v, i2) => ({ v, i: i2 })).sort((a, b) => a.v - b.v);
|
|
197
|
+
const r = new Array(xs.length);
|
|
198
|
+
let i = 0;
|
|
199
|
+
while (i < indexed.length) {
|
|
200
|
+
let j = i;
|
|
201
|
+
while (j + 1 < indexed.length && indexed[j + 1].v === indexed[i].v) j++;
|
|
202
|
+
const avg = (i + j) / 2 + 1;
|
|
203
|
+
for (let k = i; k <= j; k++) r[indexed[k].i] = avg;
|
|
204
|
+
i = j + 1;
|
|
205
|
+
}
|
|
206
|
+
return r;
|
|
207
|
+
}
|
|
208
|
+
function pearsonR(a, b) {
|
|
209
|
+
if (a.length !== b.length || a.length < 2) return Number.NaN;
|
|
210
|
+
const n = a.length;
|
|
211
|
+
const meanA = a.reduce((s, v) => s + v, 0) / n;
|
|
212
|
+
const meanB = b.reduce((s, v) => s + v, 0) / n;
|
|
213
|
+
let num = 0;
|
|
214
|
+
let varA = 0;
|
|
215
|
+
let varB = 0;
|
|
216
|
+
for (let i = 0; i < n; i++) {
|
|
217
|
+
const da = a[i] - meanA;
|
|
218
|
+
const db = b[i] - meanB;
|
|
219
|
+
num += da * db;
|
|
220
|
+
varA += da * da;
|
|
221
|
+
varB += db * db;
|
|
222
|
+
}
|
|
223
|
+
if (varA === 0 || varB === 0) return varA === 0 && varB === 0 ? 1 : 0;
|
|
224
|
+
return num / Math.sqrt(varA * varB);
|
|
225
|
+
}
|
|
226
|
+
function spearmanR(a, b) {
|
|
227
|
+
if (a.length !== b.length || a.length < 2) return Number.NaN;
|
|
228
|
+
return pearsonR(ranks(a), ranks(b));
|
|
229
|
+
}
|
|
230
|
+
function weightedComposite(input) {
|
|
231
|
+
const entries = Object.entries(input.weights);
|
|
232
|
+
if (entries.length === 0) {
|
|
233
|
+
throw new Error("weightedComposite: `weights` is empty \u2014 nothing to combine");
|
|
234
|
+
}
|
|
235
|
+
let weightedSum = 0;
|
|
236
|
+
let weightTotal = 0;
|
|
237
|
+
for (const [dim, weight] of entries) {
|
|
238
|
+
if (weight < 0) {
|
|
239
|
+
throw new Error(`weightedComposite: weight for '${dim}' is negative (${weight})`);
|
|
240
|
+
}
|
|
241
|
+
if (!(dim in input.dims)) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`weightedComposite: weighted dimension '${dim}' is absent from \`dims\` \u2014 refusing to renormalise onto a different denominator`
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
weightedSum += input.dims[dim] * weight;
|
|
247
|
+
weightTotal += weight;
|
|
248
|
+
}
|
|
249
|
+
if (weightTotal === 0) {
|
|
250
|
+
throw new Error("weightedComposite: weights sum to 0 \u2014 composite is undefined");
|
|
251
|
+
}
|
|
252
|
+
const composite = weightedSum / weightTotal;
|
|
253
|
+
return input.threshold === void 0 ? { composite } : { composite, pass: composite >= input.threshold };
|
|
254
|
+
}
|
|
255
|
+
function corpusInterRaterAgreement(records, opts = {}) {
|
|
256
|
+
if (records.length === 0) {
|
|
257
|
+
throw new ValidationError("corpusInterRaterAgreement: no score records supplied");
|
|
258
|
+
}
|
|
259
|
+
const judgesSeen = /* @__PURE__ */ new Set();
|
|
260
|
+
const dimsSeen = /* @__PURE__ */ new Set();
|
|
261
|
+
const grid = /* @__PURE__ */ new Map();
|
|
262
|
+
for (const r of records) {
|
|
263
|
+
if (!Number.isFinite(r.score)) {
|
|
264
|
+
throw new ValidationError(
|
|
265
|
+
`corpusInterRaterAgreement: non-finite score for (item=${r.itemId}, judge=${r.judgeName}, dim=${r.dimension})`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
judgesSeen.add(r.judgeName);
|
|
269
|
+
dimsSeen.add(r.dimension);
|
|
270
|
+
const byJudge = grid.get(r.dimension) ?? /* @__PURE__ */ new Map();
|
|
271
|
+
const byItem = byJudge.get(r.judgeName) ?? /* @__PURE__ */ new Map();
|
|
272
|
+
if (byItem.has(r.itemId)) {
|
|
273
|
+
throw new ValidationError(
|
|
274
|
+
`corpusInterRaterAgreement: duplicate record for (item=${r.itemId}, judge=${r.judgeName}, dim=${r.dimension})`
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
byItem.set(r.itemId, r.score);
|
|
278
|
+
byJudge.set(r.judgeName, byItem);
|
|
279
|
+
grid.set(r.dimension, byJudge);
|
|
280
|
+
}
|
|
281
|
+
const targetDims = opts.dimensions ?? [...dimsSeen].sort();
|
|
282
|
+
for (const d of targetDims) {
|
|
283
|
+
if (!dimsSeen.has(d)) {
|
|
284
|
+
throw new ValidationError(
|
|
285
|
+
`corpusInterRaterAgreement: dimension '${d}' was requested but no records carry it`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const targetJudges = opts.judges ? [...opts.judges] : [...judgesSeen].sort();
|
|
290
|
+
for (const j of targetJudges) {
|
|
291
|
+
if (!judgesSeen.has(j)) {
|
|
292
|
+
throw new ValidationError(
|
|
293
|
+
`corpusInterRaterAgreement: judge '${j}' was requested but produced no records`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (targetJudges.length < 2) {
|
|
298
|
+
throw new ValidationError(
|
|
299
|
+
`corpusInterRaterAgreement: need \u22652 judges, got ${targetJudges.length}`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
const perDimension = [];
|
|
303
|
+
const iccs = [];
|
|
304
|
+
const kappas = [];
|
|
305
|
+
for (const dim of targetDims) {
|
|
306
|
+
const byJudge = grid.get(dim);
|
|
307
|
+
const judgeItemCounts = {};
|
|
308
|
+
for (const j of targetJudges) {
|
|
309
|
+
const m = byJudge.get(j);
|
|
310
|
+
judgeItemCounts[j] = m?.size ?? 0;
|
|
311
|
+
}
|
|
312
|
+
const emptyJudges = targetJudges.filter((j) => judgeItemCounts[j] === 0);
|
|
313
|
+
if (emptyJudges.length > 0) {
|
|
314
|
+
throw new ValidationError(
|
|
315
|
+
`corpusInterRaterAgreement: dimension '${dim}' has no scores from judge(s) ${emptyJudges.join(", ")} (counts: ${JSON.stringify(judgeItemCounts)})`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
let commonItems = null;
|
|
319
|
+
for (const j of targetJudges) {
|
|
320
|
+
const ids = new Set(byJudge.get(j).keys());
|
|
321
|
+
if (commonItems === null) {
|
|
322
|
+
commonItems = ids;
|
|
323
|
+
} else {
|
|
324
|
+
const prev = commonItems;
|
|
325
|
+
commonItems = new Set([...prev].filter((x) => ids.has(x)));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const sortedItems = [...commonItems ?? /* @__PURE__ */ new Set()].sort();
|
|
329
|
+
if (sortedItems.length < 2) {
|
|
330
|
+
throw new ValidationError(
|
|
331
|
+
`corpusInterRaterAgreement: dimension '${dim}' has ${sortedItems.length} item(s) rated by all ${targetJudges.length} judges (need \u22652)`
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
const matrix = sortedItems.map(
|
|
335
|
+
(itemId) => targetJudges.map((j) => byJudge.get(j).get(itemId))
|
|
336
|
+
);
|
|
337
|
+
const agreement = continuousAgreement(matrix, opts);
|
|
338
|
+
perDimension.push({
|
|
339
|
+
...agreement,
|
|
340
|
+
dimension: dim,
|
|
341
|
+
itemIds: sortedItems,
|
|
342
|
+
judgeIds: [...targetJudges]
|
|
343
|
+
});
|
|
344
|
+
if (Number.isFinite(agreement.icc)) iccs.push(agreement.icc);
|
|
345
|
+
if (Number.isFinite(agreement.weightedKappa)) kappas.push(agreement.weightedKappa);
|
|
346
|
+
}
|
|
347
|
+
const mean = (xs) => xs.length === 0 ? Number.NaN : xs.reduce((a, b) => a + b, 0) / xs.length;
|
|
348
|
+
return {
|
|
349
|
+
perDimension,
|
|
350
|
+
overallIcc: mean(iccs),
|
|
351
|
+
overallWeightedKappa: mean(kappas),
|
|
352
|
+
dimensions: targetDims,
|
|
353
|
+
judgeIds: targetJudges
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function corpusInterRaterAgreementFromJudgeScores(itemsScores, opts = {}) {
|
|
357
|
+
const records = [];
|
|
358
|
+
const seen = /* @__PURE__ */ new Set();
|
|
359
|
+
for (const { itemId, scores } of itemsScores) {
|
|
360
|
+
if (seen.has(itemId)) {
|
|
361
|
+
throw new ValidationError(
|
|
362
|
+
`corpusInterRaterAgreementFromJudgeScores: duplicate itemId '${itemId}'`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
seen.add(itemId);
|
|
366
|
+
for (const s of scores) {
|
|
367
|
+
records.push({
|
|
368
|
+
itemId,
|
|
369
|
+
judgeName: s.judgeName,
|
|
370
|
+
dimension: s.dimension,
|
|
371
|
+
score: s.score
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return corpusInterRaterAgreement(records, opts);
|
|
376
|
+
}
|
|
377
|
+
function studentTCdf(t, df) {
|
|
378
|
+
if (df <= 0) return 0.5;
|
|
379
|
+
if (df > 100) return normalCdf(t);
|
|
380
|
+
const x = df / (df + t * t);
|
|
381
|
+
const a = df / 2;
|
|
382
|
+
const b = 0.5;
|
|
383
|
+
const ib = incompleteBeta(x, a, b);
|
|
384
|
+
return t >= 0 ? 1 - 0.5 * ib : 0.5 * ib;
|
|
385
|
+
}
|
|
386
|
+
function incompleteBeta(x, a, b) {
|
|
387
|
+
if (x <= 0) return 0;
|
|
388
|
+
if (x >= 1) return 1;
|
|
389
|
+
const lnBeta = lnGamma(a) + lnGamma(b) - lnGamma(a + b);
|
|
390
|
+
const front = Math.exp(Math.log(x) * a + Math.log(1 - x) * b - lnBeta) / a;
|
|
391
|
+
const maxIter = 200;
|
|
392
|
+
const eps = 3e-7;
|
|
393
|
+
let c = 1;
|
|
394
|
+
let d = 1 - (a + b) * x / (a + 1);
|
|
395
|
+
if (Math.abs(d) < 1e-30) d = 1e-30;
|
|
396
|
+
d = 1 / d;
|
|
397
|
+
let f = d;
|
|
398
|
+
for (let m = 1; m <= maxIter; m++) {
|
|
399
|
+
const m2 = 2 * m;
|
|
400
|
+
let num = m * (b - m) * x / ((a + m2 - 1) * (a + m2));
|
|
401
|
+
d = 1 + num * d;
|
|
402
|
+
if (Math.abs(d) < 1e-30) d = 1e-30;
|
|
403
|
+
c = 1 + num / c;
|
|
404
|
+
if (Math.abs(c) < 1e-30) c = 1e-30;
|
|
405
|
+
d = 1 / d;
|
|
406
|
+
f *= d * c;
|
|
407
|
+
num = -((a + m) * (a + b + m) * x) / ((a + m2) * (a + m2 + 1));
|
|
408
|
+
d = 1 + num * d;
|
|
409
|
+
if (Math.abs(d) < 1e-30) d = 1e-30;
|
|
410
|
+
c = 1 + num / c;
|
|
411
|
+
if (Math.abs(c) < 1e-30) c = 1e-30;
|
|
412
|
+
d = 1 / d;
|
|
413
|
+
const delta = d * c;
|
|
414
|
+
f *= delta;
|
|
415
|
+
if (Math.abs(delta - 1) < eps) break;
|
|
416
|
+
}
|
|
417
|
+
return front * f;
|
|
418
|
+
}
|
|
419
|
+
function lnGamma(z) {
|
|
420
|
+
const g = 7;
|
|
421
|
+
const coefs = [
|
|
422
|
+
0.9999999999998099,
|
|
423
|
+
676.5203681218851,
|
|
424
|
+
-1259.1392167224028,
|
|
425
|
+
771.3234287776531,
|
|
426
|
+
-176.6150291621406,
|
|
427
|
+
12.507343278686905,
|
|
428
|
+
-0.13857109526572012,
|
|
429
|
+
9984369578019572e-21,
|
|
430
|
+
15056327351493116e-23
|
|
431
|
+
];
|
|
432
|
+
if (z < 0.5) {
|
|
433
|
+
return Math.log(Math.PI / Math.sin(Math.PI * z)) - lnGamma(1 - z);
|
|
434
|
+
}
|
|
435
|
+
z -= 1;
|
|
436
|
+
let x = coefs[0];
|
|
437
|
+
for (let i = 1; i < g + 2; i++) x += coefs[i] / (z + i);
|
|
438
|
+
const t = z + g + 0.5;
|
|
439
|
+
return 0.5 * Math.log(2 * Math.PI) + (z + 0.5) * Math.log(t) - t + Math.log(x);
|
|
440
|
+
}
|
|
441
|
+
function normalCdf(x) {
|
|
442
|
+
const a1 = 0.254829592;
|
|
443
|
+
const a2 = -0.284496736;
|
|
444
|
+
const a3 = 1.421413741;
|
|
445
|
+
const a4 = -1.453152027;
|
|
446
|
+
const a5 = 1.061405429;
|
|
447
|
+
const p = 0.3275911;
|
|
448
|
+
const sign = x < 0 ? -1 : 1;
|
|
449
|
+
const absX = Math.abs(x);
|
|
450
|
+
const t = 1 / (1 + p * absX);
|
|
451
|
+
const y = 1 - ((((a5 * t + a4) * t + a3) * t + a2) * t + a1) * t * Math.exp(-absX * absX / 2);
|
|
452
|
+
return 0.5 * (1 + sign * y);
|
|
453
|
+
}
|
|
454
|
+
function requiredSampleSize(opts) {
|
|
455
|
+
const effect = opts.effect;
|
|
456
|
+
if (!Number.isFinite(effect) || effect <= 0) return Infinity;
|
|
457
|
+
const alpha = opts.alpha ?? 0.05;
|
|
458
|
+
const power = opts.power ?? 0.8;
|
|
459
|
+
const twoSided = opts.twoSided ?? true;
|
|
460
|
+
const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
|
|
461
|
+
const zBeta = zQuantile(power);
|
|
462
|
+
const n = 2 * ((zAlpha + zBeta) / effect) ** 2;
|
|
463
|
+
return Math.ceil(n);
|
|
464
|
+
}
|
|
465
|
+
function pairedMde(opts) {
|
|
466
|
+
if (!Number.isFinite(opts.nPaired) || opts.nPaired <= 0) return Infinity;
|
|
467
|
+
const alpha = opts.alpha ?? 0.05;
|
|
468
|
+
const power = opts.power ?? 0.8;
|
|
469
|
+
const twoSided = opts.twoSided ?? true;
|
|
470
|
+
const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
|
|
471
|
+
const zBeta = zQuantile(power);
|
|
472
|
+
return (zAlpha + zBeta) / Math.sqrt(opts.nPaired);
|
|
473
|
+
}
|
|
474
|
+
function mcnemarRequiredN(opts) {
|
|
475
|
+
const { p10, p01 } = opts;
|
|
476
|
+
if (p10 < 0 || p01 < 0 || p10 + p01 > 1) {
|
|
477
|
+
throw new Error(`mcnemarRequiredN: require p10,p01 \u2265 0 and p10+p01 \u2264 1 (got ${p10}, ${p01})`);
|
|
478
|
+
}
|
|
479
|
+
const delta = p10 - p01;
|
|
480
|
+
if (delta === 0) return Infinity;
|
|
481
|
+
const alpha = opts.alpha ?? 0.05;
|
|
482
|
+
const power = opts.power ?? 0.8;
|
|
483
|
+
const twoSided = opts.twoSided ?? true;
|
|
484
|
+
const pDisc = p10 + p01;
|
|
485
|
+
const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
|
|
486
|
+
const zBeta = zQuantile(power);
|
|
487
|
+
const n = (zAlpha * Math.sqrt(pDisc) + zBeta * Math.sqrt(Math.max(0, pDisc - delta * delta))) ** 2 / (delta * delta);
|
|
488
|
+
return Math.ceil(n);
|
|
489
|
+
}
|
|
490
|
+
function mcnemarPower(opts) {
|
|
491
|
+
const { p10, p01, nPairs } = opts;
|
|
492
|
+
if (p10 < 0 || p01 < 0 || p10 + p01 > 1) {
|
|
493
|
+
throw new Error(`mcnemarPower: require p10,p01 \u2265 0 and p10+p01 \u2264 1 (got ${p10}, ${p01})`);
|
|
494
|
+
}
|
|
495
|
+
const alpha = opts.alpha ?? 0.05;
|
|
496
|
+
const twoSided = opts.twoSided ?? true;
|
|
497
|
+
const delta = p10 - p01;
|
|
498
|
+
if (delta === 0 || nPairs <= 0) return alpha;
|
|
499
|
+
const pDisc = p10 + p01;
|
|
500
|
+
const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
|
|
501
|
+
const denom = Math.sqrt(Math.max(1e-12, pDisc - delta * delta));
|
|
502
|
+
const zBeta = (Math.sqrt(nPairs) * Math.abs(delta) - zAlpha * Math.sqrt(pDisc)) / denom;
|
|
503
|
+
return Math.min(1, Math.max(0, normalCdf(zBeta)));
|
|
504
|
+
}
|
|
505
|
+
function bonferroni(pValues, alpha = 0.05) {
|
|
506
|
+
const k = pValues.length;
|
|
507
|
+
const adjusted = pValues.map((p) => Math.min(1, p * k));
|
|
508
|
+
const significant = adjusted.map((p) => p < alpha);
|
|
509
|
+
return { adjusted, significant };
|
|
510
|
+
}
|
|
511
|
+
function holm(pValues, alpha = 0.05) {
|
|
512
|
+
if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
|
|
513
|
+
throw new ValidationError(`holm: alpha must be in (0,1), got ${alpha}`);
|
|
514
|
+
}
|
|
515
|
+
for (const [index, pValue] of pValues.entries()) {
|
|
516
|
+
if (!Number.isFinite(pValue) || pValue < 0 || pValue > 1) {
|
|
517
|
+
throw new ValidationError(`holm: pValues[${index}] must be in [0,1], got ${pValue}`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const count = pValues.length;
|
|
521
|
+
if (count === 0) return { adjusted: [], significant: [] };
|
|
522
|
+
const ordered = pValues.map((pValue, index) => ({ pValue, index })).sort((a, b) => a.pValue - b.pValue || a.index - b.index);
|
|
523
|
+
const adjusted = new Array(count);
|
|
524
|
+
let previous = 0;
|
|
525
|
+
for (let rank = 0; rank < count; rank++) {
|
|
526
|
+
const entry = ordered[rank];
|
|
527
|
+
const stepAdjusted = Math.min(1, entry.pValue * (count - rank));
|
|
528
|
+
previous = Math.max(previous, stepAdjusted);
|
|
529
|
+
adjusted[entry.index] = previous;
|
|
530
|
+
}
|
|
531
|
+
return { adjusted, significant: adjusted.map((pValue) => pValue <= alpha) };
|
|
532
|
+
}
|
|
533
|
+
function benjaminiHochberg(pValues, fdr = 0.05) {
|
|
534
|
+
const n = pValues.length;
|
|
535
|
+
if (n === 0) return { qValues: [], significant: [] };
|
|
536
|
+
const indexed = pValues.map((p, i) => ({ p, i })).sort((a, b) => a.p - b.p);
|
|
537
|
+
const q = new Array(n);
|
|
538
|
+
let minRight = 1;
|
|
539
|
+
for (let k = n - 1; k >= 0; k--) {
|
|
540
|
+
const rank = k + 1;
|
|
541
|
+
const entry = indexed[k];
|
|
542
|
+
const raw = entry.p * n / rank;
|
|
543
|
+
const bounded = Math.min(minRight, raw);
|
|
544
|
+
minRight = bounded;
|
|
545
|
+
q[entry.i] = Math.min(1, bounded);
|
|
546
|
+
}
|
|
547
|
+
const significant = q.map((v) => v < fdr);
|
|
548
|
+
return { qValues: q, significant };
|
|
549
|
+
}
|
|
550
|
+
function pairedBootstrap(before, after, opts = {}) {
|
|
551
|
+
if (before.length !== after.length) {
|
|
552
|
+
throw new Error(`pairedBootstrap: unequal sample sizes (${before.length} vs ${after.length})`);
|
|
553
|
+
}
|
|
554
|
+
const confidence = opts.confidence ?? 0.95;
|
|
555
|
+
const resamples = opts.resamples ?? 2e3;
|
|
556
|
+
const statistic = opts.statistic ?? "median";
|
|
557
|
+
if (confidence <= 0 || confidence >= 1) {
|
|
558
|
+
throw new Error(`pairedBootstrap: confidence must be in (0,1), got ${confidence}`);
|
|
559
|
+
}
|
|
560
|
+
const n = before.length;
|
|
561
|
+
const deltas = before.map((b, i) => after[i] - b);
|
|
562
|
+
if (n === 0) {
|
|
563
|
+
return { n: 0, median: 0, mean: 0, low: 0, high: 0, confidence, resamples };
|
|
564
|
+
}
|
|
565
|
+
if (n === 1) {
|
|
566
|
+
const d = deltas[0];
|
|
567
|
+
return { n: 1, median: d, mean: d, low: d, high: d, confidence, resamples };
|
|
568
|
+
}
|
|
569
|
+
const rng = makeRng(opts.seed);
|
|
570
|
+
const samples = new Array(resamples);
|
|
571
|
+
for (let b = 0; b < resamples; b++) {
|
|
572
|
+
if (statistic === "mean") {
|
|
573
|
+
let sum = 0;
|
|
574
|
+
for (let k = 0; k < n; k++) {
|
|
575
|
+
sum += deltas[Math.floor(rng() * n)];
|
|
576
|
+
}
|
|
577
|
+
samples[b] = sum / n;
|
|
578
|
+
} else {
|
|
579
|
+
const acc = new Array(n);
|
|
580
|
+
for (let k = 0; k < n; k++) {
|
|
581
|
+
acc[k] = deltas[Math.floor(rng() * n)];
|
|
582
|
+
}
|
|
583
|
+
samples[b] = medianInPlace(acc);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
samples.sort((a, b) => a - b);
|
|
587
|
+
const alpha = 1 - confidence;
|
|
588
|
+
const lowIdx = Math.floor(alpha / 2 * resamples);
|
|
589
|
+
const highIdx = Math.min(resamples - 1, Math.ceil((1 - alpha / 2) * resamples) - 1);
|
|
590
|
+
return {
|
|
591
|
+
n,
|
|
592
|
+
median: medianInPlace([...deltas]),
|
|
593
|
+
mean: deltas.reduce((s, x) => s + x, 0) / n,
|
|
594
|
+
low: samples[lowIdx],
|
|
595
|
+
high: samples[Math.max(highIdx, lowIdx)],
|
|
596
|
+
confidence,
|
|
597
|
+
resamples
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
function pairedSignTest(differences, alternative) {
|
|
601
|
+
if (alternative !== "greater" && alternative !== "less") {
|
|
602
|
+
throw new ValidationError(
|
|
603
|
+
`pairedSignTest: alternative must be 'greater' or 'less', got ${alternative}`
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
let positive = 0;
|
|
607
|
+
let negative = 0;
|
|
608
|
+
let ties = 0;
|
|
609
|
+
for (let i = 0; i < differences.length; i++) {
|
|
610
|
+
const difference = differences[i];
|
|
611
|
+
if (!Number.isFinite(difference)) {
|
|
612
|
+
throw new ValidationError(
|
|
613
|
+
`pairedSignTest: difference at index ${i} must be finite, got ${difference}`
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
if (difference > 0) positive++;
|
|
617
|
+
else if (difference < 0) negative++;
|
|
618
|
+
else ties++;
|
|
619
|
+
}
|
|
620
|
+
const nNonTies = positive + negative;
|
|
621
|
+
const successes = alternative === "greater" ? positive : negative;
|
|
622
|
+
return {
|
|
623
|
+
n: differences.length,
|
|
624
|
+
positive,
|
|
625
|
+
negative,
|
|
626
|
+
ties,
|
|
627
|
+
nNonTies,
|
|
628
|
+
alternative,
|
|
629
|
+
pValue: binomialHalfUpperTail(successes, nNonTies)
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
function wilson(successes, n, confidence = 0.95) {
|
|
633
|
+
if (n <= 0) return { estimate: 0, lower: 0, upper: 0 };
|
|
634
|
+
if (successes < 0 || successes > n) {
|
|
635
|
+
throw new Error(`wilson: successes (${successes}) must be in [0, ${n}]`);
|
|
636
|
+
}
|
|
637
|
+
const z = zQuantile(1 - (1 - confidence) / 2);
|
|
638
|
+
const p = successes / n;
|
|
639
|
+
const z2 = z * z;
|
|
640
|
+
const denom = 1 + z2 / n;
|
|
641
|
+
const center = (p + z2 / (2 * n)) / denom;
|
|
642
|
+
const half = z * Math.sqrt((p * (1 - p) + z2 / (4 * n)) / n) / denom;
|
|
643
|
+
return {
|
|
644
|
+
estimate: p,
|
|
645
|
+
lower: Math.max(0, center - half),
|
|
646
|
+
upper: Math.min(1, center + half)
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
function mcnemar(control, treatment) {
|
|
650
|
+
if (control.length !== treatment.length) {
|
|
651
|
+
throw new Error(`mcnemar: unequal sample sizes (${control.length} vs ${treatment.length})`);
|
|
652
|
+
}
|
|
653
|
+
const n = control.length;
|
|
654
|
+
let b = 0;
|
|
655
|
+
let c = 0;
|
|
656
|
+
for (let i = 0; i < n; i++) {
|
|
657
|
+
const ctrl = control[i] ? 1 : 0;
|
|
658
|
+
const treat = treatment[i] ? 1 : 0;
|
|
659
|
+
if (treat === 1 && ctrl === 0) b++;
|
|
660
|
+
else if (treat === 0 && ctrl === 1) c++;
|
|
661
|
+
}
|
|
662
|
+
const nDiscordant = b + c;
|
|
663
|
+
const statistic = nDiscordant === 0 ? 0 : (Math.abs(b - c) - 1) ** 2 / nDiscordant;
|
|
664
|
+
return { n, nDiscordant, b, c, statistic, pValue: binomialSignTwoSided(b, c) };
|
|
665
|
+
}
|
|
666
|
+
function pairedRiskDifference(control, treatment, confidence = 0.95) {
|
|
667
|
+
if (control.length !== treatment.length) {
|
|
668
|
+
throw new Error(
|
|
669
|
+
`pairedRiskDifference: unequal sample sizes (${control.length} vs ${treatment.length})`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
const n = control.length;
|
|
673
|
+
if (n === 0) return { n: 0, b: 0, c: 0, riskDifference: 0, lower: 0, upper: 0, confidence };
|
|
674
|
+
let b = 0;
|
|
675
|
+
let c = 0;
|
|
676
|
+
for (let i = 0; i < n; i++) {
|
|
677
|
+
const ctrl = control[i] ? 1 : 0;
|
|
678
|
+
const treat = treatment[i] ? 1 : 0;
|
|
679
|
+
if (treat === 1 && ctrl === 0) b++;
|
|
680
|
+
else if (treat === 0 && ctrl === 1) c++;
|
|
681
|
+
}
|
|
682
|
+
const rd = (b - c) / n;
|
|
683
|
+
const variance = (b + c - (b - c) ** 2 / n) / (n * n);
|
|
684
|
+
const z = zQuantile(1 - (1 - confidence) / 2);
|
|
685
|
+
const half = z * Math.sqrt(Math.max(0, variance));
|
|
686
|
+
return {
|
|
687
|
+
n,
|
|
688
|
+
b,
|
|
689
|
+
c,
|
|
690
|
+
riskDifference: rd,
|
|
691
|
+
lower: Math.max(-1, rd - half),
|
|
692
|
+
upper: Math.min(1, rd + half),
|
|
693
|
+
confidence
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function passAtK(n, c, k) {
|
|
697
|
+
if (!Number.isInteger(n) || !Number.isInteger(c) || !Number.isInteger(k)) {
|
|
698
|
+
throw new Error(`passAtK: n, c, k must be integers (got n=${n}, c=${c}, k=${k})`);
|
|
699
|
+
}
|
|
700
|
+
if (k < 1 || k > n || c < 0 || c > n) {
|
|
701
|
+
throw new Error(`passAtK: require 1 \u2264 k \u2264 n and 0 \u2264 c \u2264 n (got n=${n}, c=${c}, k=${k})`);
|
|
702
|
+
}
|
|
703
|
+
if (n - c < k) return 1;
|
|
704
|
+
let prob = 1;
|
|
705
|
+
for (let i = n - c + 1; i <= n; i++) prob *= 1 - k / i;
|
|
706
|
+
return 1 - prob;
|
|
707
|
+
}
|
|
708
|
+
function binomialSignTwoSided(b, c) {
|
|
709
|
+
const nd = b + c;
|
|
710
|
+
if (nd === 0) return 1;
|
|
711
|
+
return Math.min(1, 2 * binomialHalfLowerTail(Math.min(b, c), nd));
|
|
712
|
+
}
|
|
713
|
+
function binomialHalfUpperTail(successes, n) {
|
|
714
|
+
if (successes <= 0) return 1;
|
|
715
|
+
if (successes > n) return 0;
|
|
716
|
+
if (successes <= n / 2) {
|
|
717
|
+
return Math.max(0, 1 - binomialHalfLowerTail(successes - 1, n));
|
|
718
|
+
}
|
|
719
|
+
return binomialHalfLowerTail(n - successes, n);
|
|
720
|
+
}
|
|
721
|
+
function binomialHalfLowerTail(maxSuccesses, n) {
|
|
722
|
+
if (maxSuccesses < 0) return 0;
|
|
723
|
+
if (maxSuccesses >= n) return 1;
|
|
724
|
+
if (maxSuccesses === 0) return 2 ** -n;
|
|
725
|
+
const logHalfN = n * Math.log(0.5);
|
|
726
|
+
let logTail = Number.NEGATIVE_INFINITY;
|
|
727
|
+
for (let i = 0; i <= maxSuccesses; i++) {
|
|
728
|
+
const logChoose = lnGamma(n + 1) - lnGamma(i + 1) - lnGamma(n - i + 1);
|
|
729
|
+
logTail = logAddExp(logTail, logChoose + logHalfN);
|
|
730
|
+
}
|
|
731
|
+
return Math.min(1, Math.exp(logTail));
|
|
732
|
+
}
|
|
733
|
+
function logAddExp(a, b) {
|
|
734
|
+
if (a === Number.NEGATIVE_INFINITY) return b;
|
|
735
|
+
if (b === Number.NEGATIVE_INFINITY) return a;
|
|
736
|
+
const max = Math.max(a, b);
|
|
737
|
+
const min = Math.min(a, b);
|
|
738
|
+
return max + Math.log1p(Math.exp(min - max));
|
|
739
|
+
}
|
|
740
|
+
function eProcess(opts = {}) {
|
|
741
|
+
const alpha = opts.alpha ?? 0.05;
|
|
742
|
+
const maxBet = opts.maxBet ?? 0.5;
|
|
743
|
+
const nullMean = opts.nullMean ?? 0.5;
|
|
744
|
+
if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
|
|
745
|
+
throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`);
|
|
746
|
+
}
|
|
747
|
+
if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {
|
|
748
|
+
throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`);
|
|
749
|
+
}
|
|
750
|
+
if (!Number.isFinite(maxBet) || maxBet <= 0 || maxBet >= 1 / nullMean) {
|
|
751
|
+
throw new ValidationError(
|
|
752
|
+
`eProcess: maxBet must be in (0, 1/nullMean=${(1 / nullMean).toFixed(4)}) so wealth factors stay positive, got ${maxBet}`
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
const threshold = 1 / alpha;
|
|
756
|
+
let wealth = 1;
|
|
757
|
+
let n = 0;
|
|
758
|
+
let decided = false;
|
|
759
|
+
let decidedAtN;
|
|
760
|
+
let sumX = 0;
|
|
761
|
+
let varSum = 0;
|
|
762
|
+
return {
|
|
763
|
+
update(x) {
|
|
764
|
+
if (typeof x !== "number" || !Number.isFinite(x) || x < 0 || x > 1) {
|
|
765
|
+
throw new ValidationError(
|
|
766
|
+
`eProcess: observation must be a finite number in [0,1], got ${x}`
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
const muPrev = (0.5 + sumX) / (n + 1);
|
|
770
|
+
const varPrev = (0.25 + varSum) / (n + 1);
|
|
771
|
+
const edge = muPrev - nullMean;
|
|
772
|
+
const lambda = Math.min(maxBet, Math.max(0, edge / (varPrev + edge * edge)));
|
|
773
|
+
wealth *= 1 + lambda * (x - nullMean);
|
|
774
|
+
n += 1;
|
|
775
|
+
sumX += x;
|
|
776
|
+
const muNow = (0.5 + sumX) / (n + 1);
|
|
777
|
+
varSum += (x - muNow) ** 2;
|
|
778
|
+
if (!decided && wealth >= threshold) {
|
|
779
|
+
decided = true;
|
|
780
|
+
decidedAtN = n;
|
|
781
|
+
}
|
|
782
|
+
return { wealth, n, decided };
|
|
783
|
+
},
|
|
784
|
+
state() {
|
|
785
|
+
return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN };
|
|
786
|
+
}
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
function zQuantile(p) {
|
|
790
|
+
if (p <= 0 || p >= 1) {
|
|
791
|
+
if (p === 0) return -Infinity;
|
|
792
|
+
if (p === 1) return Infinity;
|
|
793
|
+
return NaN;
|
|
794
|
+
}
|
|
795
|
+
const a = [
|
|
796
|
+
-39.69683028665376,
|
|
797
|
+
220.9460984245205,
|
|
798
|
+
-275.9285104469687,
|
|
799
|
+
138.357751867269,
|
|
800
|
+
-30.66479806614716,
|
|
801
|
+
2.506628277459239
|
|
802
|
+
];
|
|
803
|
+
const b = [
|
|
804
|
+
-54.47609879822406,
|
|
805
|
+
161.5858368580409,
|
|
806
|
+
-155.6989798598866,
|
|
807
|
+
66.80131188771972,
|
|
808
|
+
-13.28068155288572
|
|
809
|
+
];
|
|
810
|
+
const c = [
|
|
811
|
+
-0.007784894002430293,
|
|
812
|
+
-0.3223964580411365,
|
|
813
|
+
-2.400758277161838,
|
|
814
|
+
-2.549732539343734,
|
|
815
|
+
4.374664141464968,
|
|
816
|
+
2.938163982698783
|
|
817
|
+
];
|
|
818
|
+
const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
|
|
819
|
+
const pLow = 0.02425;
|
|
820
|
+
const pHigh = 1 - pLow;
|
|
821
|
+
let q;
|
|
822
|
+
let r;
|
|
823
|
+
if (p < pLow) {
|
|
824
|
+
q = Math.sqrt(-2 * Math.log(p));
|
|
825
|
+
return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
|
|
826
|
+
}
|
|
827
|
+
if (p <= pHigh) {
|
|
828
|
+
q = p - 0.5;
|
|
829
|
+
r = q * q;
|
|
830
|
+
return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
|
|
831
|
+
}
|
|
832
|
+
q = Math.sqrt(-2 * Math.log(1 - p));
|
|
833
|
+
return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
|
|
834
|
+
}
|
|
835
|
+
function medianInPlace(xs) {
|
|
836
|
+
if (xs.length === 0) return 0;
|
|
837
|
+
xs.sort((a, b) => a - b);
|
|
838
|
+
const mid = Math.floor(xs.length / 2);
|
|
839
|
+
return xs.length % 2 === 0 ? (xs[mid - 1] + xs[mid]) / 2 : xs[mid];
|
|
840
|
+
}
|
|
841
|
+
function makeRng(seed) {
|
|
842
|
+
if (seed === void 0) return Math.random;
|
|
843
|
+
return mulberry32(seed);
|
|
844
|
+
}
|
|
845
|
+
function mulberry32(seed) {
|
|
846
|
+
let s = seed | 0 || 2654435769;
|
|
847
|
+
return () => {
|
|
848
|
+
s = s + 1831565813 | 0;
|
|
849
|
+
let t = s;
|
|
850
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
851
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
852
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
853
|
+
};
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/judge-calibration.ts
|
|
857
|
+
function calibrateJudge(golden, candidate) {
|
|
858
|
+
const map = /* @__PURE__ */ new Map();
|
|
859
|
+
for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
|
|
860
|
+
for (const c of candidate) {
|
|
861
|
+
const entry = map.get(c.itemId);
|
|
862
|
+
if (entry) entry.j = c.score;
|
|
863
|
+
}
|
|
864
|
+
const common = [...map.values()].filter((v) => Number.isFinite(v.j));
|
|
865
|
+
const n = common.length;
|
|
866
|
+
if (n < 2) {
|
|
867
|
+
return { n, pearson: NaN, kappa: NaN, mae: NaN, worstItems: [] };
|
|
868
|
+
}
|
|
869
|
+
const humans = common.map((c) => c.h);
|
|
870
|
+
const judges = common.map((c) => c.j);
|
|
871
|
+
const pearson = pearsonR(humans, judges);
|
|
872
|
+
const kappa = weightedKappa(humans.map(Math.round), judges.map(Math.round));
|
|
873
|
+
const absDiffs = common.map((c) => Math.abs(c.j - c.h));
|
|
874
|
+
const mae = absDiffs.reduce((a, b) => a + b, 0) / n;
|
|
875
|
+
const worst = [...map.entries()].filter(([, v]) => Number.isFinite(v.j)).map(([itemId, v]) => ({ itemId, judge: v.j, human: v.h, delta: Math.abs(v.j - v.h) })).sort((a, b) => b.delta - a.delta).slice(0, 5);
|
|
876
|
+
return { n, pearson, kappa, mae, worstItems: worst };
|
|
877
|
+
}
|
|
878
|
+
function positionalBias(scores) {
|
|
879
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
880
|
+
for (const s of scores) {
|
|
881
|
+
const slot = pairs.get(s.itemId) ?? {};
|
|
882
|
+
if (s.positionOfAInput === "first") slot.first = s.score;
|
|
883
|
+
else if (s.positionOfAInput === "second") slot.second = s.score;
|
|
884
|
+
pairs.set(s.itemId, slot);
|
|
885
|
+
}
|
|
886
|
+
const deltas = [];
|
|
887
|
+
for (const { first, second } of pairs.values()) {
|
|
888
|
+
if (first !== void 0 && second !== void 0) deltas.push(first - second);
|
|
889
|
+
}
|
|
890
|
+
if (deltas.length === 0) return { avgDelta: 0, n: 0 };
|
|
891
|
+
return { avgDelta: deltas.reduce((a, b) => a + b, 0) / deltas.length, n: deltas.length };
|
|
892
|
+
}
|
|
893
|
+
function verbosityBias(samples) {
|
|
894
|
+
const n = samples.length;
|
|
895
|
+
if (n < 3) return { pearson: NaN, n };
|
|
896
|
+
return {
|
|
897
|
+
pearson: pearsonR(
|
|
898
|
+
samples.map((s) => s.outputLen),
|
|
899
|
+
samples.map((s) => s.score)
|
|
900
|
+
),
|
|
901
|
+
n
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function selfPreference(samples) {
|
|
905
|
+
const inF = samples.filter((s) => s.inFamily).map((s) => s.score);
|
|
906
|
+
const outF = samples.filter((s) => !s.inFamily).map((s) => s.score);
|
|
907
|
+
if (inF.length === 0 || outF.length === 0)
|
|
908
|
+
return { inFamilyMean: 0, outOfFamilyMean: 0, deltaMean: 0, n: 0 };
|
|
909
|
+
const inMean = inF.reduce((a, b) => a + b, 0) / inF.length;
|
|
910
|
+
const outMean = outF.reduce((a, b) => a + b, 0) / outF.length;
|
|
911
|
+
return {
|
|
912
|
+
inFamilyMean: inMean,
|
|
913
|
+
outOfFamilyMean: outMean,
|
|
914
|
+
deltaMean: inMean - outMean,
|
|
915
|
+
n: samples.length
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
function weightedKappa(a, b) {
|
|
919
|
+
if (a.length !== b.length || a.length === 0) return NaN;
|
|
920
|
+
const min = Math.min(...a, ...b);
|
|
921
|
+
const max = Math.max(...a, ...b);
|
|
922
|
+
const K = max - min + 1;
|
|
923
|
+
if (K < 2) return 1;
|
|
924
|
+
const observed = Array.from({ length: K }, () => new Array(K).fill(0));
|
|
925
|
+
const rowMarg = new Array(K).fill(0);
|
|
926
|
+
const colMarg = new Array(K).fill(0);
|
|
927
|
+
for (let i = 0; i < a.length; i++) {
|
|
928
|
+
const ai = a[i] - min;
|
|
929
|
+
const bi = b[i] - min;
|
|
930
|
+
const row = observed[ai];
|
|
931
|
+
row[bi] = (row[bi] ?? 0) + 1;
|
|
932
|
+
rowMarg[ai]++;
|
|
933
|
+
colMarg[bi]++;
|
|
934
|
+
}
|
|
935
|
+
let num = 0;
|
|
936
|
+
let den = 0;
|
|
937
|
+
for (let i = 0; i < K; i++) {
|
|
938
|
+
for (let j = 0; j < K; j++) {
|
|
939
|
+
const w = (i - j) ** 2 / (K - 1) ** 2;
|
|
940
|
+
const expected = rowMarg[i] * colMarg[j] / a.length;
|
|
941
|
+
num += w * observed[i][j];
|
|
942
|
+
den += w * expected;
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (den === 0) return 1;
|
|
946
|
+
return 1 - num / den;
|
|
947
|
+
}
|
|
948
|
+
function continuousAgreement(scores, opts = {}) {
|
|
949
|
+
const bootstrap = opts.bootstrap ?? 1e3;
|
|
950
|
+
const weights = opts.weights ?? "quadratic";
|
|
951
|
+
const seed = opts.seed ?? 12648430;
|
|
952
|
+
const ciLevel = opts.ciLevel ?? 0.95;
|
|
953
|
+
const matrix = scores.filter((row) => row.length >= 2 && row.every((v) => Number.isFinite(v)));
|
|
954
|
+
const raters = matrix[0]?.length ?? 0;
|
|
955
|
+
const clean = matrix.filter((row) => row.length === raters);
|
|
956
|
+
const nClean = clean.length;
|
|
957
|
+
if (nClean < 2 || raters < 2) {
|
|
958
|
+
return {
|
|
959
|
+
weightedKappa: NaN,
|
|
960
|
+
icc: NaN,
|
|
961
|
+
pearson: NaN,
|
|
962
|
+
spearman: NaN,
|
|
963
|
+
ci: { icc: [NaN, NaN], weightedKappa: [NaN, NaN] },
|
|
964
|
+
n: nClean,
|
|
965
|
+
raters
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
const kappa = continuousWeightedKappa(clean, weights);
|
|
969
|
+
const icc = icc21(clean);
|
|
970
|
+
const pearson = avgPairwise(clean, pearsonR);
|
|
971
|
+
const spearman = avgPairwise(clean, spearmanR);
|
|
972
|
+
const ciIcc = [NaN, NaN];
|
|
973
|
+
const ciKappa = [NaN, NaN];
|
|
974
|
+
if (bootstrap > 0) {
|
|
975
|
+
const rng = mulberry322(seed);
|
|
976
|
+
const iccs = [];
|
|
977
|
+
const kappas = [];
|
|
978
|
+
for (let b = 0; b < bootstrap; b++) {
|
|
979
|
+
const sample = new Array(nClean);
|
|
980
|
+
for (let i = 0; i < nClean; i++) {
|
|
981
|
+
sample[i] = clean[Math.floor(rng() * nClean)];
|
|
982
|
+
}
|
|
983
|
+
const iccB = icc21(sample);
|
|
984
|
+
const kB = continuousWeightedKappa(sample, weights);
|
|
985
|
+
if (Number.isFinite(iccB)) iccs.push(iccB);
|
|
986
|
+
if (Number.isFinite(kB)) kappas.push(kB);
|
|
987
|
+
}
|
|
988
|
+
const [lo, hi] = percentileBounds(ciLevel);
|
|
989
|
+
if (iccs.length > 0) {
|
|
990
|
+
iccs.sort((a, b) => a - b);
|
|
991
|
+
ciIcc[0] = quantile(iccs, lo);
|
|
992
|
+
ciIcc[1] = quantile(iccs, hi);
|
|
993
|
+
}
|
|
994
|
+
if (kappas.length > 0) {
|
|
995
|
+
kappas.sort((a, b) => a - b);
|
|
996
|
+
ciKappa[0] = quantile(kappas, lo);
|
|
997
|
+
ciKappa[1] = quantile(kappas, hi);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return {
|
|
1001
|
+
weightedKappa: kappa,
|
|
1002
|
+
icc,
|
|
1003
|
+
pearson,
|
|
1004
|
+
spearman,
|
|
1005
|
+
ci: { icc: ciIcc, weightedKappa: ciKappa },
|
|
1006
|
+
n: nClean,
|
|
1007
|
+
raters
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function calibrateJudgeContinuous(golden, candidate, opts = {}) {
|
|
1011
|
+
const base = calibrateJudge(golden, candidate);
|
|
1012
|
+
const map = /* @__PURE__ */ new Map();
|
|
1013
|
+
for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
|
|
1014
|
+
for (const c of candidate) {
|
|
1015
|
+
const entry = map.get(c.itemId);
|
|
1016
|
+
if (entry) entry.j = c.score;
|
|
1017
|
+
}
|
|
1018
|
+
const rows = [];
|
|
1019
|
+
for (const v of map.values()) {
|
|
1020
|
+
if (Number.isFinite(v.j)) rows.push([v.h, v.j]);
|
|
1021
|
+
}
|
|
1022
|
+
const agreement = continuousAgreement(rows, opts);
|
|
1023
|
+
return {
|
|
1024
|
+
...base,
|
|
1025
|
+
weightedKappaContinuous: agreement.weightedKappa,
|
|
1026
|
+
icc: agreement.icc,
|
|
1027
|
+
spearman: agreement.spearman,
|
|
1028
|
+
ci: agreement.ci
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
function continuousWeightedKappa(rows, scheme) {
|
|
1032
|
+
if (rows.length === 0) return NaN;
|
|
1033
|
+
const raters = rows[0].length;
|
|
1034
|
+
if (raters < 2) return NaN;
|
|
1035
|
+
const wFn = scheme === "linear" ? (x, y) => Math.abs(x - y) : (x, y) => (x - y) ** 2;
|
|
1036
|
+
let sum = 0;
|
|
1037
|
+
let pairs = 0;
|
|
1038
|
+
for (let r1 = 0; r1 < raters; r1++) {
|
|
1039
|
+
for (let r2 = r1 + 1; r2 < raters; r2++) {
|
|
1040
|
+
const a = rows.map((row) => row[r1]);
|
|
1041
|
+
const b = rows.map((row) => row[r2]);
|
|
1042
|
+
const n = a.length;
|
|
1043
|
+
let obs = 0;
|
|
1044
|
+
for (let i = 0; i < n; i++) obs += wFn(a[i], b[i]);
|
|
1045
|
+
obs /= n;
|
|
1046
|
+
let exp = 0;
|
|
1047
|
+
for (let i = 0; i < n; i++) {
|
|
1048
|
+
for (let j = 0; j < n; j++) exp += wFn(a[i], b[j]);
|
|
1049
|
+
}
|
|
1050
|
+
exp /= n * n;
|
|
1051
|
+
if (exp === 0) {
|
|
1052
|
+
sum += obs === 0 ? 1 : 0;
|
|
1053
|
+
} else {
|
|
1054
|
+
sum += 1 - obs / exp;
|
|
1055
|
+
}
|
|
1056
|
+
pairs++;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return pairs === 0 ? NaN : sum / pairs;
|
|
1060
|
+
}
|
|
1061
|
+
function icc21(rows) {
|
|
1062
|
+
const n = rows.length;
|
|
1063
|
+
if (n < 2) return NaN;
|
|
1064
|
+
const k = rows[0].length;
|
|
1065
|
+
if (k < 2) return NaN;
|
|
1066
|
+
const rowMeans = rows.map((row) => row.reduce((s, v) => s + v, 0) / k);
|
|
1067
|
+
const colMeans = new Array(k).fill(0);
|
|
1068
|
+
for (let j = 0; j < k; j++) {
|
|
1069
|
+
let s = 0;
|
|
1070
|
+
for (let i = 0; i < n; i++) s += rows[i][j];
|
|
1071
|
+
colMeans[j] = s / n;
|
|
1072
|
+
}
|
|
1073
|
+
let grand = 0;
|
|
1074
|
+
for (let i = 0; i < n; i++) grand += rowMeans[i];
|
|
1075
|
+
grand /= n;
|
|
1076
|
+
let ssR = 0;
|
|
1077
|
+
for (let i = 0; i < n; i++) ssR += (rowMeans[i] - grand) ** 2;
|
|
1078
|
+
ssR *= k;
|
|
1079
|
+
let ssC = 0;
|
|
1080
|
+
for (let j = 0; j < k; j++) ssC += (colMeans[j] - grand) ** 2;
|
|
1081
|
+
ssC *= n;
|
|
1082
|
+
let ssT = 0;
|
|
1083
|
+
for (let i = 0; i < n; i++) {
|
|
1084
|
+
for (let j = 0; j < k; j++) ssT += (rows[i][j] - grand) ** 2;
|
|
1085
|
+
}
|
|
1086
|
+
const ssE = ssT - ssR - ssC;
|
|
1087
|
+
const dfR = n - 1;
|
|
1088
|
+
const dfC = k - 1;
|
|
1089
|
+
const dfE = (n - 1) * (k - 1);
|
|
1090
|
+
const msR = ssR / dfR;
|
|
1091
|
+
const msC = ssC / dfC;
|
|
1092
|
+
const msE = dfE > 0 ? ssE / dfE : 0;
|
|
1093
|
+
const denom = msR + (k - 1) * msE + k * (msC - msE) / n;
|
|
1094
|
+
if (denom === 0) {
|
|
1095
|
+
return msR === 0 && msE === 0 ? 1 : 0;
|
|
1096
|
+
}
|
|
1097
|
+
return (msR - msE) / denom;
|
|
1098
|
+
}
|
|
1099
|
+
function avgPairwise(rows, fn) {
|
|
1100
|
+
const k = rows[0]?.length ?? 0;
|
|
1101
|
+
if (k < 2) return NaN;
|
|
1102
|
+
let sum = 0;
|
|
1103
|
+
let pairs = 0;
|
|
1104
|
+
for (let i = 0; i < k; i++) {
|
|
1105
|
+
for (let j = i + 1; j < k; j++) {
|
|
1106
|
+
const a = rows.map((row) => row[i]);
|
|
1107
|
+
const b = rows.map((row) => row[j]);
|
|
1108
|
+
const r = fn(a, b);
|
|
1109
|
+
if (Number.isFinite(r)) {
|
|
1110
|
+
sum += r;
|
|
1111
|
+
pairs++;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
return pairs === 0 ? NaN : sum / pairs;
|
|
1116
|
+
}
|
|
1117
|
+
function mulberry322(seed) {
|
|
1118
|
+
let a = seed >>> 0;
|
|
1119
|
+
return () => {
|
|
1120
|
+
a = a + 1831565813 >>> 0;
|
|
1121
|
+
let t = a;
|
|
1122
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
1123
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
1124
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
function percentileBounds(ciLevel) {
|
|
1128
|
+
const tail = (1 - ciLevel) / 2;
|
|
1129
|
+
return [tail, 1 - tail];
|
|
1130
|
+
}
|
|
1131
|
+
function quantile(sorted, q) {
|
|
1132
|
+
if (sorted.length === 0) return NaN;
|
|
1133
|
+
if (sorted.length === 1) return sorted[0];
|
|
1134
|
+
const pos = q * (sorted.length - 1);
|
|
1135
|
+
const lo = Math.floor(pos);
|
|
1136
|
+
const hi = Math.ceil(pos);
|
|
1137
|
+
if (lo === hi) return sorted[lo];
|
|
1138
|
+
const frac = pos - lo;
|
|
1139
|
+
return sorted[lo] * (1 - frac) + sorted[hi] * frac;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
export {
|
|
1143
|
+
calibrateJudge,
|
|
1144
|
+
positionalBias,
|
|
1145
|
+
verbosityBias,
|
|
1146
|
+
selfPreference,
|
|
1147
|
+
continuousAgreement,
|
|
1148
|
+
calibrateJudgeContinuous,
|
|
1149
|
+
normalizeScores,
|
|
1150
|
+
weightedMean,
|
|
1151
|
+
confidenceInterval,
|
|
1152
|
+
interRaterReliability,
|
|
1153
|
+
mannWhitneyU,
|
|
1154
|
+
partialCredit,
|
|
1155
|
+
pairedTTest,
|
|
1156
|
+
wilcoxonSignedRank,
|
|
1157
|
+
cohensD,
|
|
1158
|
+
cliffsDelta,
|
|
1159
|
+
interpretCliffs,
|
|
1160
|
+
ranks,
|
|
1161
|
+
pearsonR,
|
|
1162
|
+
spearmanR,
|
|
1163
|
+
weightedComposite,
|
|
1164
|
+
corpusInterRaterAgreement,
|
|
1165
|
+
corpusInterRaterAgreementFromJudgeScores,
|
|
1166
|
+
requiredSampleSize,
|
|
1167
|
+
pairedMde,
|
|
1168
|
+
mcnemarRequiredN,
|
|
1169
|
+
mcnemarPower,
|
|
1170
|
+
bonferroni,
|
|
1171
|
+
holm,
|
|
1172
|
+
benjaminiHochberg,
|
|
1173
|
+
pairedBootstrap,
|
|
1174
|
+
pairedSignTest,
|
|
1175
|
+
wilson,
|
|
1176
|
+
mcnemar,
|
|
1177
|
+
pairedRiskDifference,
|
|
1178
|
+
passAtK,
|
|
1179
|
+
eProcess,
|
|
1180
|
+
mulberry32
|
|
1181
|
+
};
|
|
1182
|
+
//# sourceMappingURL=chunk-PJQFMIOX.js.map
|