diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2018-06-23 14:08:12 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2018-12-13 17:09:22 +0100 |
| commit | 362a324b3329bdcc8f20f1d0865fce52ec9e8898 (patch) | |
| tree | c931af0c0d8588c47f791b85d3faeef55117ce5b /src | |
| parent | e721ba94e5113e567283724f3d30c51929bbf287 (diff) | |
| download | brokentalents-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.vue | 8 | ||||
| -rw-r--r-- | src/ReportService.js | 14 | ||||
| -rw-r--r-- | src/ReportTable.vue | 13 |
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> |
