@tangle-network/agent-eval 0.95.1 → 0.96.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/http.d.ts +1 -1
- package/dist/adapters/langchain.d.ts +1 -1
- package/dist/adapters/otel.d.ts +1 -1
- package/dist/analyst/index.js +1 -1
- package/dist/belief-state/index.js +1 -1
- package/dist/builder-eval/index.js +4 -29
- package/dist/builder-eval/index.js.map +1 -1
- package/dist/campaign/index.d.ts +6 -6
- package/dist/campaign/index.js +5 -5
- package/dist/{chunk-AQ5WQAIV.js → chunk-3NHEO6ZC.js} +2 -2
- package/dist/chunk-3NHEO6ZC.js.map +1 -0
- package/dist/{chunk-URWVKRCS.js → chunk-6GT4NI4V.js} +2 -2
- package/dist/{chunk-5HRORJQY.js → chunk-AIGWQEME.js} +5 -16
- package/dist/{chunk-5HRORJQY.js.map → chunk-AIGWQEME.js.map} +1 -1
- package/dist/{chunk-2T4EZACH.js → chunk-HRGTA6U5.js} +2 -2
- package/dist/{chunk-56GC6VYO.js → chunk-HRGUJTER.js} +669 -665
- package/dist/chunk-HRGUJTER.js.map +1 -0
- package/dist/{chunk-NACM5RS7.js → chunk-IH7LYRHL.js} +2 -2
- package/dist/{chunk-7QTQKIDD.js → chunk-JMIUM2HE.js} +3 -3
- package/dist/{chunk-YRZ4M5GS.js → chunk-NF7OZ4J7.js} +7 -29
- package/dist/chunk-NF7OZ4J7.js.map +1 -0
- package/dist/{chunk-X74V6ESX.js → chunk-OKQ2LAT7.js} +2 -2
- package/dist/{chunk-Z6L6YSU6.js → chunk-QZYXA7ZO.js} +11 -45
- package/dist/chunk-QZYXA7ZO.js.map +1 -0
- package/dist/{chunk-KKWJD5E6.js → chunk-RPZMBW27.js} +5 -5
- package/dist/{chunk-QTMYW64F.js → chunk-VDGPPGE3.js} +2 -2
- package/dist/contract/index.d.ts +144 -9
- package/dist/contract/index.js +152 -8
- package/dist/contract/index.js.map +1 -1
- package/dist/diagnose.js +1 -1
- package/dist/{gepa-C1NCIZ9o.d.ts → gepa-Dprxvz8r.d.ts} +2 -2
- package/dist/hosted/index.d.ts +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +15 -9
- package/dist/index.js.map +1 -1
- package/dist/meta-eval/index.d.ts +1 -1
- package/dist/meta-eval/index.js +6 -28
- package/dist/meta-eval/index.js.map +1 -1
- package/dist/multishot/index.d.ts +1 -1
- package/dist/openapi.json +1 -1
- package/dist/pipelines/index.js +5 -19
- package/dist/pipelines/index.js.map +1 -1
- package/dist/{provenance-CncDq9qE.d.ts → provenance-DJ--Jcbg.d.ts} +3 -3
- package/dist/reporting.d.ts +1 -1
- package/dist/reporting.js +4 -4
- package/dist/rl.d.ts +1 -1
- package/dist/rl.js +5 -5
- package/dist/{run-campaign-WXY7KI67.js → run-campaign-OWCFOEQG.js} +3 -3
- package/dist/{statistics-CCJpTGOS.d.ts → statistics-xP-cWc5k.d.ts} +17 -1
- package/dist/{types-DQRY8ZT-.d.ts → types-BMahhhio.d.ts} +1 -1
- package/dist/workflow/index.d.ts +1 -1
- package/dist/workflow/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-56GC6VYO.js.map +0 -1
- package/dist/chunk-AQ5WQAIV.js.map +0 -1
- package/dist/chunk-YRZ4M5GS.js.map +0 -1
- package/dist/chunk-Z6L6YSU6.js.map +0 -1
- /package/dist/{chunk-URWVKRCS.js.map → chunk-6GT4NI4V.js.map} +0 -0
- /package/dist/{chunk-2T4EZACH.js.map → chunk-HRGTA6U5.js.map} +0 -0
- /package/dist/{chunk-NACM5RS7.js.map → chunk-IH7LYRHL.js.map} +0 -0
- /package/dist/{chunk-7QTQKIDD.js.map → chunk-JMIUM2HE.js.map} +0 -0
- /package/dist/{chunk-X74V6ESX.js.map → chunk-OKQ2LAT7.js.map} +0 -0
- /package/dist/{chunk-KKWJD5E6.js.map → chunk-RPZMBW27.js.map} +0 -0
- /package/dist/{chunk-QTMYW64F.js.map → chunk-VDGPPGE3.js.map} +0 -0
- /package/dist/{run-campaign-WXY7KI67.js.map → run-campaign-OWCFOEQG.js.map} +0 -0
|
@@ -2,435 +2,115 @@ import {
|
|
|
2
2
|
ValidationError
|
|
3
3
|
} from "./chunk-3BFEG2F6.js";
|
|
4
4
|
|
|
5
|
-
// src/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (n < 2) {
|
|
16
|
-
return { n, pearson: NaN, kappa: NaN, mae: NaN, worstItems: [] };
|
|
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;
|
|
17
15
|
}
|
|
18
|
-
|
|
19
|
-
const judges = common.map((c) => c.j);
|
|
20
|
-
const pearson = pearsonR(humans, judges);
|
|
21
|
-
const kappa = weightedKappa(humans.map(Math.round), judges.map(Math.round));
|
|
22
|
-
const absDiffs = common.map((c) => Math.abs(c.j - c.h));
|
|
23
|
-
const mae = absDiffs.reduce((a, b) => a + b, 0) / n;
|
|
24
|
-
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);
|
|
25
|
-
return { n, pearson, kappa, mae, worstItems: worst };
|
|
16
|
+
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
26
17
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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);
|
|
38
32
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const n = samples.length;
|
|
44
|
-
if (n < 3) return { pearson: NaN, n };
|
|
45
|
-
return {
|
|
46
|
-
pearson: pearsonR(
|
|
47
|
-
samples.map((s) => s.outputLen),
|
|
48
|
-
samples.map((s) => s.score)
|
|
49
|
-
),
|
|
50
|
-
n
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function selfPreference(samples) {
|
|
54
|
-
const inF = samples.filter((s) => s.inFamily).map((s) => s.score);
|
|
55
|
-
const outF = samples.filter((s) => !s.inFamily).map((s) => s.score);
|
|
56
|
-
if (inF.length === 0 || outF.length === 0)
|
|
57
|
-
return { inFamilyMean: 0, outOfFamilyMean: 0, deltaMean: 0, n: 0 };
|
|
58
|
-
const inMean = inF.reduce((a, b) => a + b, 0) / inF.length;
|
|
59
|
-
const outMean = outF.reduce((a, b) => a + b, 0) / outF.length;
|
|
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;
|
|
60
37
|
return {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
n: samples.length
|
|
38
|
+
mean,
|
|
39
|
+
lower: bootstrapMeans[lowerIdx],
|
|
40
|
+
upper: bootstrapMeans[Math.min(upperIdx, B - 1)]
|
|
65
41
|
};
|
|
66
42
|
}
|
|
67
|
-
function
|
|
68
|
-
if (
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (dA === 0 || dB === 0) return dA === 0 && dB === 0 ? 1 : 0;
|
|
80
|
-
return num / Math.sqrt(dA * dB);
|
|
81
|
-
}
|
|
82
|
-
function weightedKappa(a, b) {
|
|
83
|
-
if (a.length !== b.length || a.length === 0) return NaN;
|
|
84
|
-
const min = Math.min(...a, ...b);
|
|
85
|
-
const max = Math.max(...a, ...b);
|
|
86
|
-
const K = max - min + 1;
|
|
87
|
-
if (K < 2) return 1;
|
|
88
|
-
const observed = Array.from({ length: K }, () => new Array(K).fill(0));
|
|
89
|
-
const rowMarg = new Array(K).fill(0);
|
|
90
|
-
const colMarg = new Array(K).fill(0);
|
|
91
|
-
for (let i = 0; i < a.length; i++) {
|
|
92
|
-
const ai = a[i] - min;
|
|
93
|
-
const bi = b[i] - min;
|
|
94
|
-
const row = observed[ai];
|
|
95
|
-
row[bi] = (row[bi] ?? 0) + 1;
|
|
96
|
-
rowMarg[ai]++;
|
|
97
|
-
colMarg[bi]++;
|
|
98
|
-
}
|
|
99
|
-
let num = 0;
|
|
100
|
-
let den = 0;
|
|
101
|
-
for (let i = 0; i < K; i++) {
|
|
102
|
-
for (let j = 0; j < K; j++) {
|
|
103
|
-
const w = (i - j) ** 2 / (K - 1) ** 2;
|
|
104
|
-
const expected = rowMarg[i] * colMarg[j] / a.length;
|
|
105
|
-
num += w * observed[i][j];
|
|
106
|
-
den += w * expected;
|
|
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
|
+
}
|
|
107
55
|
}
|
|
108
56
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const clean = matrix.filter((row) => row.length === raters);
|
|
120
|
-
const nClean = clean.length;
|
|
121
|
-
if (nClean < 2 || raters < 2) {
|
|
122
|
-
return {
|
|
123
|
-
weightedKappa: NaN,
|
|
124
|
-
icc: NaN,
|
|
125
|
-
pearson: NaN,
|
|
126
|
-
spearman: NaN,
|
|
127
|
-
ci: { icc: [NaN, NaN], weightedKappa: [NaN, NaN] },
|
|
128
|
-
n: nClean,
|
|
129
|
-
raters
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
const kappa = continuousWeightedKappa(clean, weights);
|
|
133
|
-
const icc = icc21(clean);
|
|
134
|
-
const pearson = avgPairwise(clean, pearsonR);
|
|
135
|
-
const spearman = avgPairwise(clean, spearmanR);
|
|
136
|
-
const ciIcc = [NaN, NaN];
|
|
137
|
-
const ciKappa = [NaN, NaN];
|
|
138
|
-
if (bootstrap > 0) {
|
|
139
|
-
const rng = mulberry32(seed);
|
|
140
|
-
const iccs = [];
|
|
141
|
-
const kappas = [];
|
|
142
|
-
for (let b = 0; b < bootstrap; b++) {
|
|
143
|
-
const sample = new Array(nClean);
|
|
144
|
-
for (let i = 0; i < nClean; i++) {
|
|
145
|
-
sample[i] = clean[Math.floor(rng() * nClean)];
|
|
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
|
+
}
|
|
146
67
|
}
|
|
147
|
-
const iccB = icc21(sample);
|
|
148
|
-
const kB = continuousWeightedKappa(sample, weights);
|
|
149
|
-
if (Number.isFinite(iccB)) iccs.push(iccB);
|
|
150
|
-
if (Number.isFinite(kB)) kappas.push(kB);
|
|
151
|
-
}
|
|
152
|
-
const [lo, hi] = percentileBounds(ciLevel);
|
|
153
|
-
if (iccs.length > 0) {
|
|
154
|
-
iccs.sort((a, b) => a - b);
|
|
155
|
-
ciIcc[0] = quantile(iccs, lo);
|
|
156
|
-
ciIcc[1] = quantile(iccs, hi);
|
|
157
68
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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++;
|
|
162
78
|
}
|
|
163
79
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
pearson,
|
|
168
|
-
spearman,
|
|
169
|
-
ci: { icc: ciIcc, weightedKappa: ciKappa },
|
|
170
|
-
n: nClean,
|
|
171
|
-
raters
|
|
172
|
-
};
|
|
80
|
+
expectedDisagreement = expectedCount > 0 ? expectedDisagreement / expectedCount : 0;
|
|
81
|
+
if (expectedDisagreement === 0) return 1;
|
|
82
|
+
return 1 - observedDisagreement / expectedDisagreement;
|
|
173
83
|
}
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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;
|
|
181
100
|
}
|
|
182
|
-
|
|
183
|
-
for (
|
|
184
|
-
if (
|
|
101
|
+
let r1 = 0;
|
|
102
|
+
for (let k = 0; k < combined.length; k++) {
|
|
103
|
+
if (combined[k].group === "a") r1 += ranks2[k];
|
|
185
104
|
}
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
function continuousWeightedKappa(rows, scheme) {
|
|
196
|
-
if (rows.length === 0) return NaN;
|
|
197
|
-
const raters = rows[0].length;
|
|
198
|
-
if (raters < 2) return NaN;
|
|
199
|
-
const wFn = scheme === "linear" ? (x, y) => Math.abs(x - y) : (x, y) => (x - y) ** 2;
|
|
200
|
-
let sum = 0;
|
|
201
|
-
let pairs = 0;
|
|
202
|
-
for (let r1 = 0; r1 < raters; r1++) {
|
|
203
|
-
for (let r2 = r1 + 1; r2 < raters; r2++) {
|
|
204
|
-
const a = rows.map((row) => row[r1]);
|
|
205
|
-
const b = rows.map((row) => row[r2]);
|
|
206
|
-
const n = a.length;
|
|
207
|
-
let obs = 0;
|
|
208
|
-
for (let i = 0; i < n; i++) obs += wFn(a[i], b[i]);
|
|
209
|
-
obs /= n;
|
|
210
|
-
let exp = 0;
|
|
211
|
-
for (let i = 0; i < n; i++) {
|
|
212
|
-
for (let j = 0; j < n; j++) exp += wFn(a[i], b[j]);
|
|
213
|
-
}
|
|
214
|
-
exp /= n * n;
|
|
215
|
-
if (exp === 0) {
|
|
216
|
-
sum += obs === 0 ? 1 : 0;
|
|
217
|
-
} else {
|
|
218
|
-
sum += 1 - obs / exp;
|
|
219
|
-
}
|
|
220
|
-
pairs++;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return pairs === 0 ? NaN : sum / pairs;
|
|
224
|
-
}
|
|
225
|
-
function icc21(rows) {
|
|
226
|
-
const n = rows.length;
|
|
227
|
-
if (n < 2) return NaN;
|
|
228
|
-
const k = rows[0].length;
|
|
229
|
-
if (k < 2) return NaN;
|
|
230
|
-
const rowMeans = rows.map((row) => row.reduce((s, v) => s + v, 0) / k);
|
|
231
|
-
const colMeans = new Array(k).fill(0);
|
|
232
|
-
for (let j = 0; j < k; j++) {
|
|
233
|
-
let s = 0;
|
|
234
|
-
for (let i = 0; i < n; i++) s += rows[i][j];
|
|
235
|
-
colMeans[j] = s / n;
|
|
236
|
-
}
|
|
237
|
-
let grand = 0;
|
|
238
|
-
for (let i = 0; i < n; i++) grand += rowMeans[i];
|
|
239
|
-
grand /= n;
|
|
240
|
-
let ssR = 0;
|
|
241
|
-
for (let i = 0; i < n; i++) ssR += (rowMeans[i] - grand) ** 2;
|
|
242
|
-
ssR *= k;
|
|
243
|
-
let ssC = 0;
|
|
244
|
-
for (let j = 0; j < k; j++) ssC += (colMeans[j] - grand) ** 2;
|
|
245
|
-
ssC *= n;
|
|
246
|
-
let ssT = 0;
|
|
247
|
-
for (let i = 0; i < n; i++) {
|
|
248
|
-
for (let j = 0; j < k; j++) ssT += (rows[i][j] - grand) ** 2;
|
|
249
|
-
}
|
|
250
|
-
const ssE = ssT - ssR - ssC;
|
|
251
|
-
const dfR = n - 1;
|
|
252
|
-
const dfC = k - 1;
|
|
253
|
-
const dfE = (n - 1) * (k - 1);
|
|
254
|
-
const msR = ssR / dfR;
|
|
255
|
-
const msC = ssC / dfC;
|
|
256
|
-
const msE = dfE > 0 ? ssE / dfE : 0;
|
|
257
|
-
const denom = msR + (k - 1) * msE + k * (msC - msE) / n;
|
|
258
|
-
if (denom === 0) {
|
|
259
|
-
return msR === 0 && msE === 0 ? 1 : 0;
|
|
260
|
-
}
|
|
261
|
-
return (msR - msE) / denom;
|
|
262
|
-
}
|
|
263
|
-
function avgPairwise(rows, fn) {
|
|
264
|
-
const k = rows[0]?.length ?? 0;
|
|
265
|
-
if (k < 2) return NaN;
|
|
266
|
-
let sum = 0;
|
|
267
|
-
let pairs = 0;
|
|
268
|
-
for (let i = 0; i < k; i++) {
|
|
269
|
-
for (let j = i + 1; j < k; j++) {
|
|
270
|
-
const a = rows.map((row) => row[i]);
|
|
271
|
-
const b = rows.map((row) => row[j]);
|
|
272
|
-
const r = fn(a, b);
|
|
273
|
-
if (Number.isFinite(r)) {
|
|
274
|
-
sum += r;
|
|
275
|
-
pairs++;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
return pairs === 0 ? NaN : sum / pairs;
|
|
280
|
-
}
|
|
281
|
-
function spearmanR(a, b) {
|
|
282
|
-
if (a.length !== b.length || a.length < 2) return NaN;
|
|
283
|
-
return pearsonR(rankWithTies(a), rankWithTies(b));
|
|
284
|
-
}
|
|
285
|
-
function rankWithTies(xs) {
|
|
286
|
-
const n = xs.length;
|
|
287
|
-
const indexed = xs.map((v, i2) => ({ v, i: i2 }));
|
|
288
|
-
indexed.sort((x, y) => x.v - y.v);
|
|
289
|
-
const ranks = new Array(n).fill(0);
|
|
290
|
-
let i = 0;
|
|
291
|
-
while (i < n) {
|
|
292
|
-
let j = i;
|
|
293
|
-
while (j + 1 < n && indexed[j + 1].v === indexed[i].v) j++;
|
|
294
|
-
const avg = (i + j) / 2 + 1;
|
|
295
|
-
for (let k = i; k <= j; k++) ranks[indexed[k].i] = avg;
|
|
296
|
-
i = j + 1;
|
|
297
|
-
}
|
|
298
|
-
return ranks;
|
|
299
|
-
}
|
|
300
|
-
function mulberry32(seed) {
|
|
301
|
-
let a = seed >>> 0;
|
|
302
|
-
return () => {
|
|
303
|
-
a = a + 1831565813 >>> 0;
|
|
304
|
-
let t = a;
|
|
305
|
-
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
306
|
-
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
307
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
function percentileBounds(ciLevel) {
|
|
311
|
-
const tail = (1 - ciLevel) / 2;
|
|
312
|
-
return [tail, 1 - tail];
|
|
313
|
-
}
|
|
314
|
-
function quantile(sorted, q) {
|
|
315
|
-
if (sorted.length === 0) return NaN;
|
|
316
|
-
if (sorted.length === 1) return sorted[0];
|
|
317
|
-
const pos = q * (sorted.length - 1);
|
|
318
|
-
const lo = Math.floor(pos);
|
|
319
|
-
const hi = Math.ceil(pos);
|
|
320
|
-
if (lo === hi) return sorted[lo];
|
|
321
|
-
const frac = pos - lo;
|
|
322
|
-
return sorted[lo] * (1 - frac) + sorted[hi] * frac;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// src/statistics.ts
|
|
326
|
-
var normalizeScores = (scores) => scores;
|
|
327
|
-
function weightedMean(scores) {
|
|
328
|
-
if (scores.length === 0) return 0;
|
|
329
|
-
let totalWeight = 0;
|
|
330
|
-
let weightedSum = 0;
|
|
331
|
-
for (const { score, weight } of scores) {
|
|
332
|
-
const w = weight ?? 1;
|
|
333
|
-
weightedSum += score * w;
|
|
334
|
-
totalWeight += w;
|
|
335
|
-
}
|
|
336
|
-
return totalWeight > 0 ? weightedSum / totalWeight : 0;
|
|
337
|
-
}
|
|
338
|
-
function confidenceInterval(scores, confidence = 0.95, opts = {}) {
|
|
339
|
-
if (scores.length === 0) return { mean: 0, lower: 0, upper: 0 };
|
|
340
|
-
if (scores.length === 1) return { mean: scores[0], lower: scores[0], upper: scores[0] };
|
|
341
|
-
const n = scores.length;
|
|
342
|
-
const mean = scores.reduce((a, b) => a + b, 0) / n;
|
|
343
|
-
const B = opts.resamples ?? 1e3;
|
|
344
|
-
const rng = makeRng(opts.seed);
|
|
345
|
-
const bootstrapMeans = [];
|
|
346
|
-
for (let i = 0; i < B; i++) {
|
|
347
|
-
let sum = 0;
|
|
348
|
-
for (let j = 0; j < n; j++) {
|
|
349
|
-
sum += scores[Math.floor(rng() * n)];
|
|
350
|
-
}
|
|
351
|
-
bootstrapMeans.push(sum / n);
|
|
352
|
-
}
|
|
353
|
-
bootstrapMeans.sort((a, b) => a - b);
|
|
354
|
-
const alpha = 1 - confidence;
|
|
355
|
-
const lowerIdx = Math.floor(alpha / 2 * B);
|
|
356
|
-
const upperIdx = Math.floor((1 - alpha / 2) * B) - 1;
|
|
357
|
-
return {
|
|
358
|
-
mean,
|
|
359
|
-
lower: bootstrapMeans[lowerIdx],
|
|
360
|
-
upper: bootstrapMeans[Math.min(upperIdx, B - 1)]
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
function interRaterReliability(judgeScores) {
|
|
364
|
-
if (judgeScores.length < 2) return 1;
|
|
365
|
-
const dimensionMap = /* @__PURE__ */ new Map();
|
|
366
|
-
for (const judgeSet of judgeScores) {
|
|
367
|
-
for (const s of judgeSet) {
|
|
368
|
-
if (!dimensionMap.has(s.dimension)) dimensionMap.set(s.dimension, []);
|
|
369
|
-
const arr = dimensionMap.get(s.dimension);
|
|
370
|
-
if (arr.length === 0 || arr[arr.length - 1].length >= judgeScores.length) {
|
|
371
|
-
arr.push([s.score]);
|
|
372
|
-
} else {
|
|
373
|
-
arr[arr.length - 1].push(s.score);
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
const allValues = [];
|
|
378
|
-
const pairDiffs = [];
|
|
379
|
-
for (const items of dimensionMap.values()) {
|
|
380
|
-
for (const ratings of items) {
|
|
381
|
-
if (ratings.length < 2) continue;
|
|
382
|
-
for (const v of ratings) allValues.push(v);
|
|
383
|
-
for (let i = 0; i < ratings.length; i++) {
|
|
384
|
-
for (let j = i + 1; j < ratings.length; j++) {
|
|
385
|
-
pairDiffs.push((ratings[i] - ratings[j]) ** 2);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
if (pairDiffs.length === 0 || allValues.length < 2) return 1;
|
|
391
|
-
const observedDisagreement = pairDiffs.reduce((a, b) => a + b, 0) / pairDiffs.length;
|
|
392
|
-
let expectedDisagreement = 0;
|
|
393
|
-
let expectedCount = 0;
|
|
394
|
-
for (let i = 0; i < allValues.length; i++) {
|
|
395
|
-
for (let j = i + 1; j < allValues.length; j++) {
|
|
396
|
-
expectedDisagreement += (allValues[i] - allValues[j]) ** 2;
|
|
397
|
-
expectedCount++;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
expectedDisagreement = expectedCount > 0 ? expectedDisagreement / expectedCount : 0;
|
|
401
|
-
if (expectedDisagreement === 0) return 1;
|
|
402
|
-
return 1 - observedDisagreement / expectedDisagreement;
|
|
403
|
-
}
|
|
404
|
-
function mannWhitneyU(a, b) {
|
|
405
|
-
if (a.length === 0 || b.length === 0) return { u: 0, p: 1 };
|
|
406
|
-
const n1 = a.length;
|
|
407
|
-
const n2 = b.length;
|
|
408
|
-
const combined = [
|
|
409
|
-
...a.map((v) => ({ v, group: "a" })),
|
|
410
|
-
...b.map((v) => ({ v, group: "b" }))
|
|
411
|
-
].sort((x, y) => x.v - y.v);
|
|
412
|
-
const ranks = new Array(combined.length);
|
|
413
|
-
let i = 0;
|
|
414
|
-
while (i < combined.length) {
|
|
415
|
-
let j = i;
|
|
416
|
-
while (j < combined.length && combined[j].v === combined[i].v) j++;
|
|
417
|
-
const avgRank = (i + 1 + j) / 2;
|
|
418
|
-
for (let k = i; k < j; k++) ranks[k] = avgRank;
|
|
419
|
-
i = j;
|
|
420
|
-
}
|
|
421
|
-
let r1 = 0;
|
|
422
|
-
for (let k = 0; k < combined.length; k++) {
|
|
423
|
-
if (combined[k].group === "a") r1 += ranks[k];
|
|
424
|
-
}
|
|
425
|
-
const u1 = r1 - n1 * (n1 + 1) / 2;
|
|
426
|
-
const u2 = n1 * n2 - u1;
|
|
427
|
-
const u = Math.min(u1, u2);
|
|
428
|
-
const mu = n1 * n2 / 2;
|
|
429
|
-
const sigma = Math.sqrt(n1 * n2 * (n1 + n2 + 1) / 12);
|
|
430
|
-
if (sigma === 0) return { u, p: 1 };
|
|
431
|
-
const z = Math.abs(u - mu) / sigma;
|
|
432
|
-
const p = 2 * (1 - normalCdf(z));
|
|
433
|
-
return { u, p };
|
|
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 };
|
|
434
114
|
}
|
|
435
115
|
function partialCredit(current, target) {
|
|
436
116
|
if (target <= 0) return 1;
|
|
@@ -464,17 +144,17 @@ function wilcoxonSignedRank(before, after) {
|
|
|
464
144
|
const n = diffs.length;
|
|
465
145
|
if (n < 6) return { w: 0, p: 1 };
|
|
466
146
|
const absRanks = diffs.map((d, i2) => ({ abs: Math.abs(d), sign: Math.sign(d), i: i2 })).sort((a, b) => a.abs - b.abs);
|
|
467
|
-
const
|
|
147
|
+
const ranks2 = new Array(n);
|
|
468
148
|
let i = 0;
|
|
469
149
|
while (i < n) {
|
|
470
150
|
let j = i;
|
|
471
151
|
while (j < n && absRanks[j].abs === absRanks[i].abs) j++;
|
|
472
152
|
const avg = (i + 1 + j) / 2;
|
|
473
|
-
for (let k = i; k < j; k++)
|
|
153
|
+
for (let k = i; k < j; k++) ranks2[absRanks[k].i] = avg;
|
|
474
154
|
i = j;
|
|
475
155
|
}
|
|
476
156
|
let wPlus = 0;
|
|
477
|
-
for (let k = 0; k < n; k++) if (diffs[k] > 0) wPlus +=
|
|
157
|
+
for (let k = 0; k < n; k++) if (diffs[k] > 0) wPlus += ranks2[k];
|
|
478
158
|
const mean = n * (n + 1) / 4;
|
|
479
159
|
const variance = n * (n + 1) * (2 * n + 1) / 24;
|
|
480
160
|
const z = (wPlus - mean) / Math.sqrt(variance);
|
|
@@ -512,6 +192,41 @@ function interpretCliffs(delta) {
|
|
|
512
192
|
if (d < 0.474) return "medium";
|
|
513
193
|
return "large";
|
|
514
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
|
+
}
|
|
515
230
|
function weightedComposite(input) {
|
|
516
231
|
const entries = Object.entries(input.weights);
|
|
517
232
|
if (entries.length === 0) {
|
|
@@ -777,292 +492,578 @@ function mcnemarPower(opts) {
|
|
|
777
492
|
if (p10 < 0 || p01 < 0 || p10 + p01 > 1) {
|
|
778
493
|
throw new Error(`mcnemarPower: require p10,p01 \u2265 0 and p10+p01 \u2264 1 (got ${p10}, ${p01})`);
|
|
779
494
|
}
|
|
780
|
-
const alpha = opts.alpha ?? 0.05;
|
|
781
|
-
const twoSided = opts.twoSided ?? true;
|
|
782
|
-
const delta = p10 - p01;
|
|
783
|
-
if (delta === 0 || nPairs <= 0) return alpha;
|
|
784
|
-
const pDisc = p10 + p01;
|
|
785
|
-
const zAlpha = zQuantile(twoSided ? 1 - alpha / 2 : 1 - alpha);
|
|
786
|
-
const denom = Math.sqrt(Math.max(1e-12, pDisc - delta * delta));
|
|
787
|
-
const zBeta = (Math.sqrt(nPairs) * Math.abs(delta) - zAlpha * Math.sqrt(pDisc)) / denom;
|
|
788
|
-
return Math.min(1, Math.max(0, normalCdf(zBeta)));
|
|
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 benjaminiHochberg(pValues, fdr = 0.05) {
|
|
512
|
+
const n = pValues.length;
|
|
513
|
+
if (n === 0) return { qValues: [], significant: [] };
|
|
514
|
+
const indexed = pValues.map((p, i) => ({ p, i })).sort((a, b) => a.p - b.p);
|
|
515
|
+
const q = new Array(n);
|
|
516
|
+
let minRight = 1;
|
|
517
|
+
for (let k = n - 1; k >= 0; k--) {
|
|
518
|
+
const rank = k + 1;
|
|
519
|
+
const entry = indexed[k];
|
|
520
|
+
const raw = entry.p * n / rank;
|
|
521
|
+
const bounded = Math.min(minRight, raw);
|
|
522
|
+
minRight = bounded;
|
|
523
|
+
q[entry.i] = Math.min(1, bounded);
|
|
524
|
+
}
|
|
525
|
+
const significant = q.map((v) => v < fdr);
|
|
526
|
+
return { qValues: q, significant };
|
|
527
|
+
}
|
|
528
|
+
function pairedBootstrap(before, after, opts = {}) {
|
|
529
|
+
if (before.length !== after.length) {
|
|
530
|
+
throw new Error(`pairedBootstrap: unequal sample sizes (${before.length} vs ${after.length})`);
|
|
531
|
+
}
|
|
532
|
+
const confidence = opts.confidence ?? 0.95;
|
|
533
|
+
const resamples = opts.resamples ?? 2e3;
|
|
534
|
+
const statistic = opts.statistic ?? "median";
|
|
535
|
+
if (confidence <= 0 || confidence >= 1) {
|
|
536
|
+
throw new Error(`pairedBootstrap: confidence must be in (0,1), got ${confidence}`);
|
|
537
|
+
}
|
|
538
|
+
const n = before.length;
|
|
539
|
+
const deltas = before.map((b, i) => after[i] - b);
|
|
540
|
+
if (n === 0) {
|
|
541
|
+
return { n: 0, median: 0, mean: 0, low: 0, high: 0, confidence, resamples };
|
|
542
|
+
}
|
|
543
|
+
if (n === 1) {
|
|
544
|
+
const d = deltas[0];
|
|
545
|
+
return { n: 1, median: d, mean: d, low: d, high: d, confidence, resamples };
|
|
546
|
+
}
|
|
547
|
+
const rng = makeRng(opts.seed);
|
|
548
|
+
const samples = new Array(resamples);
|
|
549
|
+
for (let b = 0; b < resamples; b++) {
|
|
550
|
+
if (statistic === "mean") {
|
|
551
|
+
let sum = 0;
|
|
552
|
+
for (let k = 0; k < n; k++) {
|
|
553
|
+
sum += deltas[Math.floor(rng() * n)];
|
|
554
|
+
}
|
|
555
|
+
samples[b] = sum / n;
|
|
556
|
+
} else {
|
|
557
|
+
const acc = new Array(n);
|
|
558
|
+
for (let k = 0; k < n; k++) {
|
|
559
|
+
acc[k] = deltas[Math.floor(rng() * n)];
|
|
560
|
+
}
|
|
561
|
+
samples[b] = medianInPlace(acc);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
samples.sort((a, b) => a - b);
|
|
565
|
+
const alpha = 1 - confidence;
|
|
566
|
+
const lowIdx = Math.floor(alpha / 2 * resamples);
|
|
567
|
+
const highIdx = Math.min(resamples - 1, Math.ceil((1 - alpha / 2) * resamples) - 1);
|
|
568
|
+
return {
|
|
569
|
+
n,
|
|
570
|
+
median: medianInPlace([...deltas]),
|
|
571
|
+
mean: deltas.reduce((s, x) => s + x, 0) / n,
|
|
572
|
+
low: samples[lowIdx],
|
|
573
|
+
high: samples[Math.max(highIdx, lowIdx)],
|
|
574
|
+
confidence,
|
|
575
|
+
resamples
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function wilson(successes, n, confidence = 0.95) {
|
|
579
|
+
if (n <= 0) return { estimate: 0, lower: 0, upper: 0 };
|
|
580
|
+
if (successes < 0 || successes > n) {
|
|
581
|
+
throw new Error(`wilson: successes (${successes}) must be in [0, ${n}]`);
|
|
582
|
+
}
|
|
583
|
+
const z = zQuantile(1 - (1 - confidence) / 2);
|
|
584
|
+
const p = successes / n;
|
|
585
|
+
const z2 = z * z;
|
|
586
|
+
const denom = 1 + z2 / n;
|
|
587
|
+
const center = (p + z2 / (2 * n)) / denom;
|
|
588
|
+
const half = z * Math.sqrt((p * (1 - p) + z2 / (4 * n)) / n) / denom;
|
|
589
|
+
return {
|
|
590
|
+
estimate: p,
|
|
591
|
+
lower: Math.max(0, center - half),
|
|
592
|
+
upper: Math.min(1, center + half)
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
function mcnemar(control, treatment) {
|
|
596
|
+
if (control.length !== treatment.length) {
|
|
597
|
+
throw new Error(`mcnemar: unequal sample sizes (${control.length} vs ${treatment.length})`);
|
|
598
|
+
}
|
|
599
|
+
const n = control.length;
|
|
600
|
+
let b = 0;
|
|
601
|
+
let c = 0;
|
|
602
|
+
for (let i = 0; i < n; i++) {
|
|
603
|
+
const ctrl = control[i] ? 1 : 0;
|
|
604
|
+
const treat = treatment[i] ? 1 : 0;
|
|
605
|
+
if (treat === 1 && ctrl === 0) b++;
|
|
606
|
+
else if (treat === 0 && ctrl === 1) c++;
|
|
607
|
+
}
|
|
608
|
+
const nDiscordant = b + c;
|
|
609
|
+
const statistic = nDiscordant === 0 ? 0 : (Math.abs(b - c) - 1) ** 2 / nDiscordant;
|
|
610
|
+
return { n, nDiscordant, b, c, statistic, pValue: binomialSignTwoSided(b, c) };
|
|
611
|
+
}
|
|
612
|
+
function pairedRiskDifference(control, treatment, confidence = 0.95) {
|
|
613
|
+
if (control.length !== treatment.length) {
|
|
614
|
+
throw new Error(
|
|
615
|
+
`pairedRiskDifference: unequal sample sizes (${control.length} vs ${treatment.length})`
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
const n = control.length;
|
|
619
|
+
if (n === 0) return { n: 0, b: 0, c: 0, riskDifference: 0, lower: 0, upper: 0, confidence };
|
|
620
|
+
let b = 0;
|
|
621
|
+
let c = 0;
|
|
622
|
+
for (let i = 0; i < n; i++) {
|
|
623
|
+
const ctrl = control[i] ? 1 : 0;
|
|
624
|
+
const treat = treatment[i] ? 1 : 0;
|
|
625
|
+
if (treat === 1 && ctrl === 0) b++;
|
|
626
|
+
else if (treat === 0 && ctrl === 1) c++;
|
|
627
|
+
}
|
|
628
|
+
const rd = (b - c) / n;
|
|
629
|
+
const variance = (b + c - (b - c) ** 2 / n) / (n * n);
|
|
630
|
+
const z = zQuantile(1 - (1 - confidence) / 2);
|
|
631
|
+
const half = z * Math.sqrt(Math.max(0, variance));
|
|
632
|
+
return {
|
|
633
|
+
n,
|
|
634
|
+
b,
|
|
635
|
+
c,
|
|
636
|
+
riskDifference: rd,
|
|
637
|
+
lower: Math.max(-1, rd - half),
|
|
638
|
+
upper: Math.min(1, rd + half),
|
|
639
|
+
confidence
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function passAtK(n, c, k) {
|
|
643
|
+
if (!Number.isInteger(n) || !Number.isInteger(c) || !Number.isInteger(k)) {
|
|
644
|
+
throw new Error(`passAtK: n, c, k must be integers (got n=${n}, c=${c}, k=${k})`);
|
|
645
|
+
}
|
|
646
|
+
if (k < 1 || k > n || c < 0 || c > n) {
|
|
647
|
+
throw new Error(`passAtK: require 1 \u2264 k \u2264 n and 0 \u2264 c \u2264 n (got n=${n}, c=${c}, k=${k})`);
|
|
648
|
+
}
|
|
649
|
+
if (n - c < k) return 1;
|
|
650
|
+
let prob = 1;
|
|
651
|
+
for (let i = n - c + 1; i <= n; i++) prob *= 1 - k / i;
|
|
652
|
+
return 1 - prob;
|
|
653
|
+
}
|
|
654
|
+
function binomialSignTwoSided(b, c) {
|
|
655
|
+
const nd = b + c;
|
|
656
|
+
if (nd === 0) return 1;
|
|
657
|
+
const k = Math.min(b, c);
|
|
658
|
+
const logHalfN = nd * Math.log(0.5);
|
|
659
|
+
let tail = 0;
|
|
660
|
+
for (let i = 0; i <= k; i++) {
|
|
661
|
+
const logChoose = lnGamma(nd + 1) - lnGamma(i + 1) - lnGamma(nd - i + 1);
|
|
662
|
+
tail += Math.exp(logChoose + logHalfN);
|
|
663
|
+
}
|
|
664
|
+
return Math.min(1, 2 * tail);
|
|
665
|
+
}
|
|
666
|
+
function eProcess(opts = {}) {
|
|
667
|
+
const alpha = opts.alpha ?? 0.05;
|
|
668
|
+
const maxBet = opts.maxBet ?? 0.5;
|
|
669
|
+
const nullMean = opts.nullMean ?? 0.5;
|
|
670
|
+
if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
|
|
671
|
+
throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`);
|
|
672
|
+
}
|
|
673
|
+
if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {
|
|
674
|
+
throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`);
|
|
675
|
+
}
|
|
676
|
+
if (!Number.isFinite(maxBet) || maxBet <= 0 || maxBet >= 1 / nullMean) {
|
|
677
|
+
throw new ValidationError(
|
|
678
|
+
`eProcess: maxBet must be in (0, 1/nullMean=${(1 / nullMean).toFixed(4)}) so wealth factors stay positive, got ${maxBet}`
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
const threshold = 1 / alpha;
|
|
682
|
+
let wealth = 1;
|
|
683
|
+
let n = 0;
|
|
684
|
+
let decided = false;
|
|
685
|
+
let decidedAtN;
|
|
686
|
+
let sumX = 0;
|
|
687
|
+
let varSum = 0;
|
|
688
|
+
return {
|
|
689
|
+
update(x) {
|
|
690
|
+
if (typeof x !== "number" || !Number.isFinite(x) || x < 0 || x > 1) {
|
|
691
|
+
throw new ValidationError(
|
|
692
|
+
`eProcess: observation must be a finite number in [0,1], got ${x}`
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
const muPrev = (0.5 + sumX) / (n + 1);
|
|
696
|
+
const varPrev = (0.25 + varSum) / (n + 1);
|
|
697
|
+
const edge = muPrev - nullMean;
|
|
698
|
+
const lambda = Math.min(maxBet, Math.max(0, edge / (varPrev + edge * edge)));
|
|
699
|
+
wealth *= 1 + lambda * (x - nullMean);
|
|
700
|
+
n += 1;
|
|
701
|
+
sumX += x;
|
|
702
|
+
const muNow = (0.5 + sumX) / (n + 1);
|
|
703
|
+
varSum += (x - muNow) ** 2;
|
|
704
|
+
if (!decided && wealth >= threshold) {
|
|
705
|
+
decided = true;
|
|
706
|
+
decidedAtN = n;
|
|
707
|
+
}
|
|
708
|
+
return { wealth, n, decided };
|
|
709
|
+
},
|
|
710
|
+
state() {
|
|
711
|
+
return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN };
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function zQuantile(p) {
|
|
716
|
+
if (p <= 0 || p >= 1) {
|
|
717
|
+
if (p === 0) return -Infinity;
|
|
718
|
+
if (p === 1) return Infinity;
|
|
719
|
+
return NaN;
|
|
720
|
+
}
|
|
721
|
+
const a = [
|
|
722
|
+
-39.69683028665376,
|
|
723
|
+
220.9460984245205,
|
|
724
|
+
-275.9285104469687,
|
|
725
|
+
138.357751867269,
|
|
726
|
+
-30.66479806614716,
|
|
727
|
+
2.506628277459239
|
|
728
|
+
];
|
|
729
|
+
const b = [
|
|
730
|
+
-54.47609879822406,
|
|
731
|
+
161.5858368580409,
|
|
732
|
+
-155.6989798598866,
|
|
733
|
+
66.80131188771972,
|
|
734
|
+
-13.28068155288572
|
|
735
|
+
];
|
|
736
|
+
const c = [
|
|
737
|
+
-0.007784894002430293,
|
|
738
|
+
-0.3223964580411365,
|
|
739
|
+
-2.400758277161838,
|
|
740
|
+
-2.549732539343734,
|
|
741
|
+
4.374664141464968,
|
|
742
|
+
2.938163982698783
|
|
743
|
+
];
|
|
744
|
+
const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
|
|
745
|
+
const pLow = 0.02425;
|
|
746
|
+
const pHigh = 1 - pLow;
|
|
747
|
+
let q;
|
|
748
|
+
let r;
|
|
749
|
+
if (p < pLow) {
|
|
750
|
+
q = Math.sqrt(-2 * Math.log(p));
|
|
751
|
+
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);
|
|
752
|
+
}
|
|
753
|
+
if (p <= pHigh) {
|
|
754
|
+
q = p - 0.5;
|
|
755
|
+
r = q * q;
|
|
756
|
+
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);
|
|
757
|
+
}
|
|
758
|
+
q = Math.sqrt(-2 * Math.log(1 - p));
|
|
759
|
+
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);
|
|
789
760
|
}
|
|
790
|
-
function
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
const
|
|
794
|
-
return
|
|
761
|
+
function medianInPlace(xs) {
|
|
762
|
+
if (xs.length === 0) return 0;
|
|
763
|
+
xs.sort((a, b) => a - b);
|
|
764
|
+
const mid = Math.floor(xs.length / 2);
|
|
765
|
+
return xs.length % 2 === 0 ? (xs[mid - 1] + xs[mid]) / 2 : xs[mid];
|
|
795
766
|
}
|
|
796
|
-
function
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
const indexed = pValues.map((p, i) => ({ p, i })).sort((a, b) => a.p - b.p);
|
|
800
|
-
const q = new Array(n);
|
|
801
|
-
let minRight = 1;
|
|
802
|
-
for (let k = n - 1; k >= 0; k--) {
|
|
803
|
-
const rank = k + 1;
|
|
804
|
-
const entry = indexed[k];
|
|
805
|
-
const raw = entry.p * n / rank;
|
|
806
|
-
const bounded = Math.min(minRight, raw);
|
|
807
|
-
minRight = bounded;
|
|
808
|
-
q[entry.i] = Math.min(1, bounded);
|
|
809
|
-
}
|
|
810
|
-
const significant = q.map((v) => v < fdr);
|
|
811
|
-
return { qValues: q, significant };
|
|
767
|
+
function makeRng(seed) {
|
|
768
|
+
if (seed === void 0) return Math.random;
|
|
769
|
+
return mulberry32(seed);
|
|
812
770
|
}
|
|
813
|
-
function
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
771
|
+
function mulberry32(seed) {
|
|
772
|
+
let s = seed | 0 || 2654435769;
|
|
773
|
+
return () => {
|
|
774
|
+
s = s + 1831565813 | 0;
|
|
775
|
+
let t = s;
|
|
776
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
777
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
778
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// src/judge-calibration.ts
|
|
783
|
+
function calibrateJudge(golden, candidate) {
|
|
784
|
+
const map = /* @__PURE__ */ new Map();
|
|
785
|
+
for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
|
|
786
|
+
for (const c of candidate) {
|
|
787
|
+
const entry = map.get(c.itemId);
|
|
788
|
+
if (entry) entry.j = c.score;
|
|
822
789
|
}
|
|
823
|
-
const
|
|
824
|
-
const
|
|
825
|
-
if (n
|
|
826
|
-
return { n
|
|
790
|
+
const common = [...map.values()].filter((v) => Number.isFinite(v.j));
|
|
791
|
+
const n = common.length;
|
|
792
|
+
if (n < 2) {
|
|
793
|
+
return { n, pearson: NaN, kappa: NaN, mae: NaN, worstItems: [] };
|
|
827
794
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
795
|
+
const humans = common.map((c) => c.h);
|
|
796
|
+
const judges = common.map((c) => c.j);
|
|
797
|
+
const pearson = pearsonR(humans, judges);
|
|
798
|
+
const kappa = weightedKappa(humans.map(Math.round), judges.map(Math.round));
|
|
799
|
+
const absDiffs = common.map((c) => Math.abs(c.j - c.h));
|
|
800
|
+
const mae = absDiffs.reduce((a, b) => a + b, 0) / n;
|
|
801
|
+
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);
|
|
802
|
+
return { n, pearson, kappa, mae, worstItems: worst };
|
|
803
|
+
}
|
|
804
|
+
function positionalBias(scores) {
|
|
805
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
806
|
+
for (const s of scores) {
|
|
807
|
+
const slot = pairs.get(s.itemId) ?? {};
|
|
808
|
+
if (s.positionOfAInput === "first") slot.first = s.score;
|
|
809
|
+
else if (s.positionOfAInput === "second") slot.second = s.score;
|
|
810
|
+
pairs.set(s.itemId, slot);
|
|
831
811
|
}
|
|
832
|
-
const
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
if (statistic === "mean") {
|
|
836
|
-
let sum = 0;
|
|
837
|
-
for (let k = 0; k < n; k++) {
|
|
838
|
-
sum += deltas[Math.floor(rng() * n)];
|
|
839
|
-
}
|
|
840
|
-
samples[b] = sum / n;
|
|
841
|
-
} else {
|
|
842
|
-
const acc = new Array(n);
|
|
843
|
-
for (let k = 0; k < n; k++) {
|
|
844
|
-
acc[k] = deltas[Math.floor(rng() * n)];
|
|
845
|
-
}
|
|
846
|
-
samples[b] = medianInPlace(acc);
|
|
847
|
-
}
|
|
812
|
+
const deltas = [];
|
|
813
|
+
for (const { first, second } of pairs.values()) {
|
|
814
|
+
if (first !== void 0 && second !== void 0) deltas.push(first - second);
|
|
848
815
|
}
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
816
|
+
if (deltas.length === 0) return { avgDelta: 0, n: 0 };
|
|
817
|
+
return { avgDelta: deltas.reduce((a, b) => a + b, 0) / deltas.length, n: deltas.length };
|
|
818
|
+
}
|
|
819
|
+
function verbosityBias(samples) {
|
|
820
|
+
const n = samples.length;
|
|
821
|
+
if (n < 3) return { pearson: NaN, n };
|
|
853
822
|
return {
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
confidence,
|
|
860
|
-
resamples
|
|
823
|
+
pearson: pearsonR(
|
|
824
|
+
samples.map((s) => s.outputLen),
|
|
825
|
+
samples.map((s) => s.score)
|
|
826
|
+
),
|
|
827
|
+
n
|
|
861
828
|
};
|
|
862
829
|
}
|
|
863
|
-
function
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
const
|
|
869
|
-
const
|
|
870
|
-
const z2 = z * z;
|
|
871
|
-
const denom = 1 + z2 / n;
|
|
872
|
-
const center = (p + z2 / (2 * n)) / denom;
|
|
873
|
-
const half = z * Math.sqrt((p * (1 - p) + z2 / (4 * n)) / n) / denom;
|
|
830
|
+
function selfPreference(samples) {
|
|
831
|
+
const inF = samples.filter((s) => s.inFamily).map((s) => s.score);
|
|
832
|
+
const outF = samples.filter((s) => !s.inFamily).map((s) => s.score);
|
|
833
|
+
if (inF.length === 0 || outF.length === 0)
|
|
834
|
+
return { inFamilyMean: 0, outOfFamilyMean: 0, deltaMean: 0, n: 0 };
|
|
835
|
+
const inMean = inF.reduce((a, b) => a + b, 0) / inF.length;
|
|
836
|
+
const outMean = outF.reduce((a, b) => a + b, 0) / outF.length;
|
|
874
837
|
return {
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
838
|
+
inFamilyMean: inMean,
|
|
839
|
+
outOfFamilyMean: outMean,
|
|
840
|
+
deltaMean: inMean - outMean,
|
|
841
|
+
n: samples.length
|
|
878
842
|
};
|
|
879
843
|
}
|
|
880
|
-
function
|
|
881
|
-
if (
|
|
882
|
-
|
|
844
|
+
function weightedKappa(a, b) {
|
|
845
|
+
if (a.length !== b.length || a.length === 0) return NaN;
|
|
846
|
+
const min = Math.min(...a, ...b);
|
|
847
|
+
const max = Math.max(...a, ...b);
|
|
848
|
+
const K = max - min + 1;
|
|
849
|
+
if (K < 2) return 1;
|
|
850
|
+
const observed = Array.from({ length: K }, () => new Array(K).fill(0));
|
|
851
|
+
const rowMarg = new Array(K).fill(0);
|
|
852
|
+
const colMarg = new Array(K).fill(0);
|
|
853
|
+
for (let i = 0; i < a.length; i++) {
|
|
854
|
+
const ai = a[i] - min;
|
|
855
|
+
const bi = b[i] - min;
|
|
856
|
+
const row = observed[ai];
|
|
857
|
+
row[bi] = (row[bi] ?? 0) + 1;
|
|
858
|
+
rowMarg[ai]++;
|
|
859
|
+
colMarg[bi]++;
|
|
883
860
|
}
|
|
884
|
-
|
|
885
|
-
let
|
|
886
|
-
let
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
861
|
+
let num = 0;
|
|
862
|
+
let den = 0;
|
|
863
|
+
for (let i = 0; i < K; i++) {
|
|
864
|
+
for (let j = 0; j < K; j++) {
|
|
865
|
+
const w = (i - j) ** 2 / (K - 1) ** 2;
|
|
866
|
+
const expected = rowMarg[i] * colMarg[j] / a.length;
|
|
867
|
+
num += w * observed[i][j];
|
|
868
|
+
den += w * expected;
|
|
869
|
+
}
|
|
892
870
|
}
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
return { n, nDiscordant, b, c, statistic, pValue: binomialSignTwoSided(b, c) };
|
|
871
|
+
if (den === 0) return 1;
|
|
872
|
+
return 1 - num / den;
|
|
896
873
|
}
|
|
897
|
-
function
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
874
|
+
function continuousAgreement(scores, opts = {}) {
|
|
875
|
+
const bootstrap = opts.bootstrap ?? 1e3;
|
|
876
|
+
const weights = opts.weights ?? "quadratic";
|
|
877
|
+
const seed = opts.seed ?? 12648430;
|
|
878
|
+
const ciLevel = opts.ciLevel ?? 0.95;
|
|
879
|
+
const matrix = scores.filter((row) => row.length >= 2 && row.every((v) => Number.isFinite(v)));
|
|
880
|
+
const raters = matrix[0]?.length ?? 0;
|
|
881
|
+
const clean = matrix.filter((row) => row.length === raters);
|
|
882
|
+
const nClean = clean.length;
|
|
883
|
+
if (nClean < 2 || raters < 2) {
|
|
884
|
+
return {
|
|
885
|
+
weightedKappa: NaN,
|
|
886
|
+
icc: NaN,
|
|
887
|
+
pearson: NaN,
|
|
888
|
+
spearman: NaN,
|
|
889
|
+
ci: { icc: [NaN, NaN], weightedKappa: [NaN, NaN] },
|
|
890
|
+
n: nClean,
|
|
891
|
+
raters
|
|
892
|
+
};
|
|
902
893
|
}
|
|
903
|
-
const
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
894
|
+
const kappa = continuousWeightedKappa(clean, weights);
|
|
895
|
+
const icc = icc21(clean);
|
|
896
|
+
const pearson = avgPairwise(clean, pearsonR);
|
|
897
|
+
const spearman = avgPairwise(clean, spearmanR);
|
|
898
|
+
const ciIcc = [NaN, NaN];
|
|
899
|
+
const ciKappa = [NaN, NaN];
|
|
900
|
+
if (bootstrap > 0) {
|
|
901
|
+
const rng = mulberry322(seed);
|
|
902
|
+
const iccs = [];
|
|
903
|
+
const kappas = [];
|
|
904
|
+
for (let b = 0; b < bootstrap; b++) {
|
|
905
|
+
const sample = new Array(nClean);
|
|
906
|
+
for (let i = 0; i < nClean; i++) {
|
|
907
|
+
sample[i] = clean[Math.floor(rng() * nClean)];
|
|
908
|
+
}
|
|
909
|
+
const iccB = icc21(sample);
|
|
910
|
+
const kB = continuousWeightedKappa(sample, weights);
|
|
911
|
+
if (Number.isFinite(iccB)) iccs.push(iccB);
|
|
912
|
+
if (Number.isFinite(kB)) kappas.push(kB);
|
|
913
|
+
}
|
|
914
|
+
const [lo, hi] = percentileBounds(ciLevel);
|
|
915
|
+
if (iccs.length > 0) {
|
|
916
|
+
iccs.sort((a, b) => a - b);
|
|
917
|
+
ciIcc[0] = quantile(iccs, lo);
|
|
918
|
+
ciIcc[1] = quantile(iccs, hi);
|
|
919
|
+
}
|
|
920
|
+
if (kappas.length > 0) {
|
|
921
|
+
kappas.sort((a, b) => a - b);
|
|
922
|
+
ciKappa[0] = quantile(kappas, lo);
|
|
923
|
+
ciKappa[1] = quantile(kappas, hi);
|
|
924
|
+
}
|
|
912
925
|
}
|
|
913
|
-
const rd = (b - c) / n;
|
|
914
|
-
const variance = (b + c - (b - c) ** 2 / n) / (n * n);
|
|
915
|
-
const z = zQuantile(1 - (1 - confidence) / 2);
|
|
916
|
-
const half = z * Math.sqrt(Math.max(0, variance));
|
|
917
926
|
return {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
927
|
+
weightedKappa: kappa,
|
|
928
|
+
icc,
|
|
929
|
+
pearson,
|
|
930
|
+
spearman,
|
|
931
|
+
ci: { icc: ciIcc, weightedKappa: ciKappa },
|
|
932
|
+
n: nClean,
|
|
933
|
+
raters
|
|
925
934
|
};
|
|
926
935
|
}
|
|
927
|
-
function
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
if (n - c < k) return 1;
|
|
935
|
-
let prob = 1;
|
|
936
|
-
for (let i = n - c + 1; i <= n; i++) prob *= 1 - k / i;
|
|
937
|
-
return 1 - prob;
|
|
938
|
-
}
|
|
939
|
-
function binomialSignTwoSided(b, c) {
|
|
940
|
-
const nd = b + c;
|
|
941
|
-
if (nd === 0) return 1;
|
|
942
|
-
const k = Math.min(b, c);
|
|
943
|
-
const logHalfN = nd * Math.log(0.5);
|
|
944
|
-
let tail = 0;
|
|
945
|
-
for (let i = 0; i <= k; i++) {
|
|
946
|
-
const logChoose = lnGamma(nd + 1) - lnGamma(i + 1) - lnGamma(nd - i + 1);
|
|
947
|
-
tail += Math.exp(logChoose + logHalfN);
|
|
948
|
-
}
|
|
949
|
-
return Math.min(1, 2 * tail);
|
|
950
|
-
}
|
|
951
|
-
function eProcess(opts = {}) {
|
|
952
|
-
const alpha = opts.alpha ?? 0.05;
|
|
953
|
-
const maxBet = opts.maxBet ?? 0.5;
|
|
954
|
-
const nullMean = opts.nullMean ?? 0.5;
|
|
955
|
-
if (!Number.isFinite(alpha) || alpha <= 0 || alpha >= 1) {
|
|
956
|
-
throw new ValidationError(`eProcess: alpha must be in (0,1), got ${alpha}`);
|
|
957
|
-
}
|
|
958
|
-
if (!Number.isFinite(nullMean) || nullMean <= 0 || nullMean >= 1) {
|
|
959
|
-
throw new ValidationError(`eProcess: nullMean must be in (0,1), got ${nullMean}`);
|
|
936
|
+
function calibrateJudgeContinuous(golden, candidate, opts = {}) {
|
|
937
|
+
const base = calibrateJudge(golden, candidate);
|
|
938
|
+
const map = /* @__PURE__ */ new Map();
|
|
939
|
+
for (const g of golden) map.set(g.itemId, { h: g.humanScore, j: NaN });
|
|
940
|
+
for (const c of candidate) {
|
|
941
|
+
const entry = map.get(c.itemId);
|
|
942
|
+
if (entry) entry.j = c.score;
|
|
960
943
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
);
|
|
944
|
+
const rows = [];
|
|
945
|
+
for (const v of map.values()) {
|
|
946
|
+
if (Number.isFinite(v.j)) rows.push([v.h, v.j]);
|
|
965
947
|
}
|
|
966
|
-
const
|
|
967
|
-
let wealth = 1;
|
|
968
|
-
let n = 0;
|
|
969
|
-
let decided = false;
|
|
970
|
-
let decidedAtN;
|
|
971
|
-
let sumX = 0;
|
|
972
|
-
let varSum = 0;
|
|
948
|
+
const agreement = continuousAgreement(rows, opts);
|
|
973
949
|
return {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
950
|
+
...base,
|
|
951
|
+
weightedKappaContinuous: agreement.weightedKappa,
|
|
952
|
+
icc: agreement.icc,
|
|
953
|
+
spearman: agreement.spearman,
|
|
954
|
+
ci: agreement.ci
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
function continuousWeightedKappa(rows, scheme) {
|
|
958
|
+
if (rows.length === 0) return NaN;
|
|
959
|
+
const raters = rows[0].length;
|
|
960
|
+
if (raters < 2) return NaN;
|
|
961
|
+
const wFn = scheme === "linear" ? (x, y) => Math.abs(x - y) : (x, y) => (x - y) ** 2;
|
|
962
|
+
let sum = 0;
|
|
963
|
+
let pairs = 0;
|
|
964
|
+
for (let r1 = 0; r1 < raters; r1++) {
|
|
965
|
+
for (let r2 = r1 + 1; r2 < raters; r2++) {
|
|
966
|
+
const a = rows.map((row) => row[r1]);
|
|
967
|
+
const b = rows.map((row) => row[r2]);
|
|
968
|
+
const n = a.length;
|
|
969
|
+
let obs = 0;
|
|
970
|
+
for (let i = 0; i < n; i++) obs += wFn(a[i], b[i]);
|
|
971
|
+
obs /= n;
|
|
972
|
+
let exp = 0;
|
|
973
|
+
for (let i = 0; i < n; i++) {
|
|
974
|
+
for (let j = 0; j < n; j++) exp += wFn(a[i], b[j]);
|
|
979
975
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
n += 1;
|
|
986
|
-
sumX += x;
|
|
987
|
-
const muNow = (0.5 + sumX) / (n + 1);
|
|
988
|
-
varSum += (x - muNow) ** 2;
|
|
989
|
-
if (!decided && wealth >= threshold) {
|
|
990
|
-
decided = true;
|
|
991
|
-
decidedAtN = n;
|
|
976
|
+
exp /= n * n;
|
|
977
|
+
if (exp === 0) {
|
|
978
|
+
sum += obs === 0 ? 1 : 0;
|
|
979
|
+
} else {
|
|
980
|
+
sum += 1 - obs / exp;
|
|
992
981
|
}
|
|
993
|
-
|
|
994
|
-
},
|
|
995
|
-
state() {
|
|
996
|
-
return { wealth, n, decided, alpha, maxBet, nullMean, threshold, decidedAtN };
|
|
982
|
+
pairs++;
|
|
997
983
|
}
|
|
998
|
-
}
|
|
984
|
+
}
|
|
985
|
+
return pairs === 0 ? NaN : sum / pairs;
|
|
999
986
|
}
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
987
|
+
function icc21(rows) {
|
|
988
|
+
const n = rows.length;
|
|
989
|
+
if (n < 2) return NaN;
|
|
990
|
+
const k = rows[0].length;
|
|
991
|
+
if (k < 2) return NaN;
|
|
992
|
+
const rowMeans = rows.map((row) => row.reduce((s, v) => s + v, 0) / k);
|
|
993
|
+
const colMeans = new Array(k).fill(0);
|
|
994
|
+
for (let j = 0; j < k; j++) {
|
|
995
|
+
let s = 0;
|
|
996
|
+
for (let i = 0; i < n; i++) s += rows[i][j];
|
|
997
|
+
colMeans[j] = s / n;
|
|
1005
998
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
];
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
-
|
|
1018
|
-
66.80131188771972,
|
|
1019
|
-
-13.28068155288572
|
|
1020
|
-
];
|
|
1021
|
-
const c = [
|
|
1022
|
-
-0.007784894002430293,
|
|
1023
|
-
-0.3223964580411365,
|
|
1024
|
-
-2.400758277161838,
|
|
1025
|
-
-2.549732539343734,
|
|
1026
|
-
4.374664141464968,
|
|
1027
|
-
2.938163982698783
|
|
1028
|
-
];
|
|
1029
|
-
const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
|
|
1030
|
-
const pLow = 0.02425;
|
|
1031
|
-
const pHigh = 1 - pLow;
|
|
1032
|
-
let q;
|
|
1033
|
-
let r;
|
|
1034
|
-
if (p < pLow) {
|
|
1035
|
-
q = Math.sqrt(-2 * Math.log(p));
|
|
1036
|
-
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);
|
|
999
|
+
let grand = 0;
|
|
1000
|
+
for (let i = 0; i < n; i++) grand += rowMeans[i];
|
|
1001
|
+
grand /= n;
|
|
1002
|
+
let ssR = 0;
|
|
1003
|
+
for (let i = 0; i < n; i++) ssR += (rowMeans[i] - grand) ** 2;
|
|
1004
|
+
ssR *= k;
|
|
1005
|
+
let ssC = 0;
|
|
1006
|
+
for (let j = 0; j < k; j++) ssC += (colMeans[j] - grand) ** 2;
|
|
1007
|
+
ssC *= n;
|
|
1008
|
+
let ssT = 0;
|
|
1009
|
+
for (let i = 0; i < n; i++) {
|
|
1010
|
+
for (let j = 0; j < k; j++) ssT += (rows[i][j] - grand) ** 2;
|
|
1037
1011
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1012
|
+
const ssE = ssT - ssR - ssC;
|
|
1013
|
+
const dfR = n - 1;
|
|
1014
|
+
const dfC = k - 1;
|
|
1015
|
+
const dfE = (n - 1) * (k - 1);
|
|
1016
|
+
const msR = ssR / dfR;
|
|
1017
|
+
const msC = ssC / dfC;
|
|
1018
|
+
const msE = dfE > 0 ? ssE / dfE : 0;
|
|
1019
|
+
const denom = msR + (k - 1) * msE + k * (msC - msE) / n;
|
|
1020
|
+
if (denom === 0) {
|
|
1021
|
+
return msR === 0 && msE === 0 ? 1 : 0;
|
|
1042
1022
|
}
|
|
1043
|
-
|
|
1044
|
-
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);
|
|
1045
|
-
}
|
|
1046
|
-
function medianInPlace(xs) {
|
|
1047
|
-
if (xs.length === 0) return 0;
|
|
1048
|
-
xs.sort((a, b) => a - b);
|
|
1049
|
-
const mid = Math.floor(xs.length / 2);
|
|
1050
|
-
return xs.length % 2 === 0 ? (xs[mid - 1] + xs[mid]) / 2 : xs[mid];
|
|
1023
|
+
return (msR - msE) / denom;
|
|
1051
1024
|
}
|
|
1052
|
-
function
|
|
1053
|
-
|
|
1054
|
-
|
|
1025
|
+
function avgPairwise(rows, fn) {
|
|
1026
|
+
const k = rows[0]?.length ?? 0;
|
|
1027
|
+
if (k < 2) return NaN;
|
|
1028
|
+
let sum = 0;
|
|
1029
|
+
let pairs = 0;
|
|
1030
|
+
for (let i = 0; i < k; i++) {
|
|
1031
|
+
for (let j = i + 1; j < k; j++) {
|
|
1032
|
+
const a = rows.map((row) => row[i]);
|
|
1033
|
+
const b = rows.map((row) => row[j]);
|
|
1034
|
+
const r = fn(a, b);
|
|
1035
|
+
if (Number.isFinite(r)) {
|
|
1036
|
+
sum += r;
|
|
1037
|
+
pairs++;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return pairs === 0 ? NaN : sum / pairs;
|
|
1055
1042
|
}
|
|
1056
1043
|
function mulberry322(seed) {
|
|
1057
|
-
let
|
|
1044
|
+
let a = seed >>> 0;
|
|
1058
1045
|
return () => {
|
|
1059
|
-
|
|
1060
|
-
let t =
|
|
1046
|
+
a = a + 1831565813 >>> 0;
|
|
1047
|
+
let t = a;
|
|
1061
1048
|
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
1062
1049
|
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
1063
1050
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1064
1051
|
};
|
|
1065
1052
|
}
|
|
1053
|
+
function percentileBounds(ciLevel) {
|
|
1054
|
+
const tail = (1 - ciLevel) / 2;
|
|
1055
|
+
return [tail, 1 - tail];
|
|
1056
|
+
}
|
|
1057
|
+
function quantile(sorted, q) {
|
|
1058
|
+
if (sorted.length === 0) return NaN;
|
|
1059
|
+
if (sorted.length === 1) return sorted[0];
|
|
1060
|
+
const pos = q * (sorted.length - 1);
|
|
1061
|
+
const lo = Math.floor(pos);
|
|
1062
|
+
const hi = Math.ceil(pos);
|
|
1063
|
+
if (lo === hi) return sorted[lo];
|
|
1064
|
+
const frac = pos - lo;
|
|
1065
|
+
return sorted[lo] * (1 - frac) + sorted[hi] * frac;
|
|
1066
|
+
}
|
|
1066
1067
|
|
|
1067
1068
|
export {
|
|
1068
1069
|
calibrateJudge,
|
|
@@ -1082,6 +1083,9 @@ export {
|
|
|
1082
1083
|
cohensD,
|
|
1083
1084
|
cliffsDelta,
|
|
1084
1085
|
interpretCliffs,
|
|
1086
|
+
ranks,
|
|
1087
|
+
pearsonR,
|
|
1088
|
+
spearmanR,
|
|
1085
1089
|
weightedComposite,
|
|
1086
1090
|
corpusInterRaterAgreement,
|
|
1087
1091
|
corpusInterRaterAgreementFromJudgeScores,
|
|
@@ -1097,6 +1101,6 @@ export {
|
|
|
1097
1101
|
pairedRiskDifference,
|
|
1098
1102
|
passAtK,
|
|
1099
1103
|
eProcess,
|
|
1100
|
-
|
|
1104
|
+
mulberry32
|
|
1101
1105
|
};
|
|
1102
|
-
//# sourceMappingURL=chunk-
|
|
1106
|
+
//# sourceMappingURL=chunk-HRGUJTER.js.map
|