76 lines
2.8 KiB
JavaScript
76 lines
2.8 KiB
JavaScript
export function ciExpectancy(rValues) {
|
|
const n = rValues.length;
|
|
if (n === 0) return { mean: 0, lo: 0, hi: 0, n: 0 };
|
|
|
|
const mean = rValues.reduce((a, b) => a + b, 0) / n;
|
|
|
|
if (n === 1) return { mean, lo: mean, hi: mean, n };
|
|
|
|
const variance = rValues.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / (n - 1);
|
|
const sd = Math.sqrt(variance);
|
|
const se = sd / Math.sqrt(n);
|
|
|
|
return { mean, lo: mean - 1.96 * se, hi: mean + 1.96 * se, n };
|
|
}
|
|
|
|
export function generateResultsTable(testResults) {
|
|
const grades = ['A', 'B', 'C', 'D'];
|
|
const grouped = {
|
|
A: { wins: 0, losses: 0, scratches: 0, rVals: [] },
|
|
B: { wins: 0, losses: 0, scratches: 0, rVals: [] },
|
|
C: { wins: 0, losses: 0, scratches: 0, rVals: [] },
|
|
D: { wins: 0, losses: 0, scratches: 0, rVals: [] }
|
|
};
|
|
|
|
for (const r of testResults) {
|
|
if (grouped[r.grade]) {
|
|
grouped[r.grade].rVals.push(r.rMultiple);
|
|
if (r.outcome === 'WIN') grouped[r.grade].wins++;
|
|
else if (r.outcome === 'LOSS') grouped[r.grade].losses++;
|
|
else grouped[r.grade].scratches++;
|
|
}
|
|
}
|
|
|
|
console.log(`\n=== OUT-OF-SAMPLE TEST RESULTS (EXPECTANCY) ===`);
|
|
console.log(`Grade\tExp(R)\t\t95% CI (Exp)\t\tWin%\tLoss%\tScratch%\tn`);
|
|
console.log(`-----------------------------------------------------------------------------------------`);
|
|
|
|
for (const g of grades) {
|
|
const st = grouped[g];
|
|
const n = st.rVals.length;
|
|
if (n === 0) continue;
|
|
|
|
const pWin = (st.wins / n) * 100;
|
|
const pLoss = (st.losses / n) * 100;
|
|
const pScratch = (st.scratches / n) * 100;
|
|
|
|
const ci = ciExpectancy(st.rVals);
|
|
|
|
const meanFmt = `${ci.mean > 0 ? '+' : ''}${ci.mean.toFixed(3)}R`;
|
|
const ciFmt = `[${ci.lo.toFixed(3)}, ${ci.hi.toFixed(3)}]`;
|
|
|
|
console.log(`${g}\t${meanFmt}\t\t${ciFmt}\t\t${pWin.toFixed(1)}%\t${pLoss.toFixed(1)}%\t${pScratch.toFixed(1)}%\t\t${n}`);
|
|
}
|
|
|
|
// Random Control = The entire test set
|
|
const allR = testResults.map(r => r.rMultiple);
|
|
const totalN = allR.length;
|
|
if (totalN > 0) {
|
|
const totalWins = testResults.filter(r => r.outcome === 'WIN').length;
|
|
const totalLosses = testResults.filter(r => r.outcome === 'LOSS').length;
|
|
const totalScratches = testResults.filter(r => r.outcome === 'SCRATCH').length;
|
|
|
|
const ciRand = ciExpectancy(allR);
|
|
const meanFmt = `${ciRand.mean > 0 ? '+' : ''}${ciRand.mean.toFixed(3)}R`;
|
|
const ciFmt = `[${ciRand.lo.toFixed(3)}, ${ciRand.hi.toFixed(3)}]`;
|
|
|
|
const pWin = (totalWins / totalN) * 100;
|
|
const pLoss = (totalLosses / totalN) * 100;
|
|
const pScratch = (totalScratches / totalN) * 100;
|
|
|
|
console.log(`Rand\t${meanFmt}\t\t${ciFmt}\t\t${pWin.toFixed(1)}%\t${pLoss.toFixed(1)}%\t${pScratch.toFixed(1)}%\t\t${totalN}`);
|
|
}
|
|
|
|
console.log(`-----------------------------------------------------------------------------------------`);
|
|
}
|