summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2018-06-23 14:08:12 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2018-12-13 17:09:22 +0100
commit362a324b3329bdcc8f20f1d0865fce52ec9e8898 (patch)
treec931af0c0d8588c47f791b85d3faeef55117ce5b /src
parente721ba94e5113e567283724f3d30c51929bbf287 (diff)
downloadbrokentalents-362a324b3329bdcc8f20f1d0865fce52ec9e8898.tar.gz
brokentalents-362a324b3329bdcc8f20f1d0865fce52ec9e8898.zip
Calculate r^2 and show 'uncertain' labels for max level stats
Diffstat (limited to 'src')
-rw-r--r--src/HeroTalentTable.vue8
-rw-r--r--src/ReportService.js14
-rw-r--r--src/ReportTable.vue13
3 files changed, 25 insertions, 10 deletions
diff --git a/src/HeroTalentTable.vue b/src/HeroTalentTable.vue
index 6bd228a..dc2098c 100644
--- a/src/HeroTalentTable.vue
+++ b/src/HeroTalentTable.vue
@@ -22,15 +22,15 @@
{{ (100 * props.row.Winner).toFixed(2) }}% <!-- No Talent -->
</template>
<template v-else>
- {{ (100 * props.row.TalentWinrateBase).toFixed(2) }}%
+ {{ (100 * props.row.TalentWinrateBase).toFixed(0) }}%
</template>
- <small v-if="props.row.SampleTooSmall">uncertain</small>
+ <small v-if="props.row.SampleTooSmall"><br />uncertain</small>
</b-table-column>
<b-table-column field="TalentWinrateMax" label="Max Level Win Rate" meta="Estimated." sortable numeric>
<template v-if="!isNaN(props.row.TalentWinrateMax)">
- {{ (100 * props.row.TalentWinrateMax).toFixed(2) }}%
- <small v-if="props.row.SampleTooSmall">uncertain</small>
+ {{ (100 * props.row.TalentWinrateMax).toFixed(0) }}%
+ <small v-if="props.row.SampleTooSmall || props.row.VarianceTooLarge"><br />uncertain</small>
</template>
</b-table-column>
</template>
diff --git a/src/ReportService.js b/src/ReportService.js
index 3a94671..3da118a 100644
--- a/src/ReportService.js
+++ b/src/ReportService.js
@@ -3,6 +3,7 @@ import * as metadata from '../data/2d73896c/metadata.json';
const POPULAR_THRESHOLD = 1.0; // percent
const PICKS_THRESHOLD = 300; // picks
+const VARIANCE_THRESHOLD = 0.25; // % minimum accuracy
const report = require('../data/2d73896c/report.json')
.filter((entry) => entry.Actor != undefined); // bad data from API downtime
@@ -63,14 +64,23 @@ for(let mode of modes) {
const slope = (n * sum_xy - sum_x * sum_y) / (n * sum_xx - sum_x * sum_x);
const intercept = (sum_y - slope * sum_x) / n;
+ // sum (actual - average)^2
+ const sstot = ys.map((y) => Math.pow(y - sum_y / n, 2)).reduce(sum, 0);
+ // sum (actual - estimated)^2
+ const ssres = ys.map((y, index) => Math.pow((intercept + slope * xs[index]) - y, 2)).reduce(sum, 0);
+ // r^2 is also correlation coefficient ^ 2
+ const rsquare = 1 - ssres / sstot;
+
return Object.assign({}, entry, {
TalentWinrateBase: intercept,
TalentWinrateScaling: slope, // to 1 = max level
TalentWinrateMax: intercept + slope,
TalentWinrateLevelScaling: slope / maps.getMaxLevel(entry),
+ TalentWinrateVariance: rsquare,
TotalPicks: sum_weights || entry.Count, // NoTalent has no weights
TotalWinner: sum_y / sum_weights || entry.Winner,
SampleTooSmall: sum_weights < PICKS_THRESHOLD,
+ VarianceTooLarge: rsquare < VARIANCE_THRESHOLD,
});
});
reports.set(mode, reportFilterModeRegressed);
@@ -100,10 +110,10 @@ for(let mode of modes) {
.filter((entry) => maps.getTalentRarity(entry.Talent) == 'Legendary' && 100 * playersPerMatch * entry.TotalPicks / totalPicks.get(mode))
.sort((entry1, entry2) => entry2.TotalWinner - entry1.TotalWinner)[0]);
topLowLevel.set(mode, reports.get(mode)
- .filter((entry) => !entry.SampleTooSmall)
+ .filter((entry) => !entry.SampleTooSmall && !entry.VarianceTooLarge)
.sort((entry1, entry2) => entry2.TalentWinrateBase - entry1.TalentWinrateBase)[0]);
topScaling.set(mode, reports.get(mode)
- .filter((entry) => !entry.SampleTooSmall)
+ .filter((entry) => !entry.SampleTooSmall && !entry.VarianceTooLarge)
.sort((entry1, entry2) => entry2.TalentWinrateLevelScaling - entry1.TalentWinrateLevelScaling)[0]);
if (actors.length == 0) {
diff --git a/src/ReportTable.vue b/src/ReportTable.vue
index fa457e6..d44bdea 100644
--- a/src/ReportTable.vue
+++ b/src/ReportTable.vue
@@ -16,7 +16,7 @@
<b-field>
<div class="control">
- <b-switch v-model="filterLowPickrate">Include entries without enough data</b-switch>
+ <b-switch v-model="filterLowPickrate">Include entries without enough data (statistics will be inaccurate)</b-switch>
</div>
</b-field>
@@ -70,18 +70,23 @@
{{ (100 * props.row.Winner).toFixed(2) }}% <!-- No Talent -->
</template>
<template v-else>
- {{ (100 * props.row.TalentWinrateBase).toFixed(2) }}%
+ {{ (100 * props.row.TalentWinrateBase).toFixed(0) }}%
</template>
</b-table-column>
<b-table-column field="TalentWinrateMax" label="Max Level Win Rate" meta="Estimated." :visible="hasTalents" sortable numeric>
<template v-if="!isNaN(props.row.TalentWinrateMax)">
- {{ (100 * props.row.TalentWinrateMax).toFixed(2) }}%
+ {{ (100 * props.row.TalentWinrateMax).toFixed(0) }}%
+ <small v-if="props.row.VarianceTooLarge"><br />uncertain</small>
</template>
</b-table-column>
+ <b-table-column field="TalentWinrateVariance" label="Variance" :visible="hasTalents" sortable numeric>
+ {{ props.row.TalentWinrateVariance.toFixed(2) }}
+ </b-table-column>
+
<b-table-column field="Winner" label="Win Rate" :visible="!hasTalents" sortable numeric>
- {{ (100 * props.row.Winner).toFixed(2) }}%
+ {{ (100 * props.row.Winner).toFixed(0) }}%
</b-table-column>
<b-table-column field="TotalPicks" label="Pick Rate" sortable numeric>