]> git.sesse.net Git - pkanalytics/commitdiff
Add per-point CIs.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 20 May 2023 21:10:34 +0000 (23:10 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 20 May 2023 21:10:34 +0000 (23:10 +0200)
ultimate.js

index 54348cdbace06e06524a88dd77c445463490e9b7..7c265c258ae6b7b406328c934cbc24bb43508e30 100644 (file)
@@ -74,7 +74,11 @@ function add_3cell_ci(tr, ci) {
        const width = 100;
        const height = 20;
        let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
-       svg.classList.add('ci');
+       if (ci.inverted === true) {
+               svg.classList.add('invertedci');
+       } else {
+               svg.classList.add('ci');
+       }
        svg.setAttribute('width', width);
        svg.setAttribute('height', height);
 
@@ -513,6 +517,32 @@ function make_efficiency_ci(points_won, points_completed, z)
        return ci;
 }
 
+// Ds, throwaways and drops can happen multiple times per point,
+// so they are Poisson distributed.
+//
+// Modified Wald (recommended by http://www.ine.pt/revstat/pdf/rs120203.pdf
+// since our rates are definitely below 2 per point).
+function make_poisson_ci(val, num, z, inverted)
+{
+       let low  = (val == 0) ? 0.0 : ((val - 0.5) - Math.sqrt(val - 0.5)) / num;
+       let high = (val == 0) ? -Math.log(0.025) / num : ((val + 0.5) + Math.sqrt(val + 0.5)) / num;
+
+       // Fix the signs so that we don't get -0.00.
+       low = Math.max(low, 0.0);
+
+       // The display range of 0 to 0.25 is fairly arbitrary. So is the desired 0.05 per point.
+       let avg = val / num;
+       return {
+               'val': avg,
+               'lower_ci': low,
+               'upper_ci': high,
+               'min': 0.0,
+               'max': 0.25,
+               'desired': 0.05,
+               'inverted': inverted,
+       };
+}
+
 function make_table_general(players) {
        let rows = [];
        {
@@ -744,24 +774,28 @@ function make_table_per_point(players) {
        let touches = 0;
        for (const [q,p] of Object.entries(players)) {
                if (q === 'globals') continue;
+
+               // Can only happen once per point, so these are binomials.
+               let ci_goals = make_binomial_ci(p.goals, p.points_played, z);
+               let ci_assists = make_binomial_ci(p.assists, p.points_played, z);
+               let ci_hockey_assists = make_binomial_ci(p.hockey_assists, p.points_played, z);
+               // Arbitrarily desire at least 10% (not everybody can score or assist).
+               ci_goals.desired = 0.1;
+               ci_assists.desired = 0.1;
+               ci_hockey_assists.desired = 0.1;
+
                let row = document.createElement('tr');
                add_3cell(row, p.name, 'name');  // TODO: number?
+               add_3cell_ci(row, ci_goals);
+               add_3cell_ci(row, ci_assists);
+               add_3cell_ci(row, ci_hockey_assists);
+               add_3cell_ci(row, make_poisson_ci(p.defenses, p.points_played, z));
+               add_3cell_ci(row, make_poisson_ci(p.throwaways, p.points_played, z, true));
+               add_3cell_ci(row, make_poisson_ci(p.drops, p.points_played, z, true));
                if (p.points_played > 0) {
-                       add_3cell(row, p.goals == 0 ? 0 : (p.goals / p.points_played).toFixed(2));
-                       add_3cell(row, p.assists == 0 ? 0 : (p.assists / p.points_played).toFixed(2));
-                       add_3cell(row, p.hockey_assists == 0 ? 0 : (p.hockey_assists / p.points_played).toFixed(2));
-                       add_3cell(row, p.defenses == 0 ? 0 : (p.defenses / p.points_played).toFixed(2));
-                       add_3cell(row, p.throwaways == 0 ? 0 : (p.throwaways / p.points_played).toFixed(2));
-                       add_3cell(row, p.drops == 0 ? 0 : (p.drops / p.points_played).toFixed(2));
                        add_3cell(row, p.touches == 0 ? 0 : (p.touches / p.points_played).toFixed(2));
                } else {
                        add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
-                       add_3cell(row, 'N/A');
                }
                rows.push(row);