Codex commited on
Commit
ddd40be
ยท
1 Parent(s): e3ed8af

Use overall K in strength map

Browse files
Files changed (1) hide show
  1. app.js +25 -12
app.js CHANGED
@@ -39,6 +39,13 @@ const state = {
39
  const $ = (id) => document.getElementById(id);
40
  const isExaone = (model) => model === "exaone-forecast" || model.startsWith("exaone-");
41
  const displayName = (model) => isExaone(model) ? "EXAONE Forecast Finance" : model;
 
 
 
 
 
 
 
42
  const finite = (v) => Number.isFinite(v);
43
  const fmt = (v, digits = 2) => finite(v) ? v.toFixed(digits) : '<span class="skip">โ€”</span>';
44
  const fmtValue = (v) => {
@@ -277,7 +284,7 @@ function detailsByScope() {
277
  for (const row of state.records) {
278
  const group = `${row.scope || "Other"} ยท ${row.category || "Other"}`;
279
  if (!grouped.has(group)) grouped.set(group, new Map());
280
- if (!grouped.get(group).has(row.detail_category)) grouped.get(group).set(row.detail_category, row.detail_category);
281
  }
282
  return [...grouped.entries()].sort((a, b) => a[0].localeCompare(b[0]));
283
  }
@@ -622,7 +629,7 @@ function fillHowtoUnits() {
622
  const tier = $("howto-tier").value || "tier1";
623
  const current = $("howto-detail").value;
624
  const details = [...new Set(state.records.filter((r) => r.model === model && r.tier === tier).map((r) => r.detail_category))].sort();
625
- $("howto-detail").innerHTML = details.map((detail) => `<option value="${detail}">${detail}</option>`).join("");
626
  if (details.includes(current)) $("howto-detail").value = current;
627
  fillHowtoFrequencies();
628
  }
@@ -768,7 +775,7 @@ function showMetricScoreDetail(model, tier, metricGroup) {
768
  && candidate.series_id === row.series_id
769
  && candidate.metric === row.metric;
770
  }).length;
771
- html += `<tr><td title="${row.category || ""}">${row.detail_category}</td><td title="${row.frequency}">${freqCode(row.frequency)}</td><td title="${row.metric}">${parts.name} <span class="dir-arrow ${direction > 0 ? "up" : "down"}">${direction > 0 ? "โ†‘" : "โ†“"}</span></td><td>${parts.type}</td><td>${parts.target}</td><td class="num">${fmtValue(row.value)}</td><td class="num">${rankText(row.rank, total)}</td></tr>`;
772
  }
773
  html += `</tbody></table><p class="note">ํ˜„์žฌ ์™ผ์ชฝ Metric ยท Detail Category ยท Frequency ํ•„ํ„ฐ ์กฐ๊ฑด ์•ˆ์—์„œ ์ด ํ‰๊ท  ์…€์„ ๊ตฌ์„ฑํ•œ ์‹ค์ œ metric ๊ฐ’๊ณผ rank์ž…๋‹ˆ๋‹ค.</p>`;
774
  openDrawer(`${displayName(model)} ยท ${metricGroupLabel(metricGroup)}`, html);
@@ -799,10 +806,16 @@ function renderStrength() {
799
  $("strength-body").innerHTML = '<p class="loading-note">์„ ํƒ๋œ ํ•„ํ„ฐ ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” cell์ด ์—†์Šต๋‹ˆ๋‹ค.</p>';
800
  return;
801
  }
802
- const statsRows = tierStats(scopedRecords);
803
- const units = [...new Map(scopedRecords.map((r) => [r.unit, r.unit_label || r.unit])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
 
 
 
 
804
  const matrix = unitK(null, scopedRecords);
805
- const overall = statsRows.sort((a, b) => compareNullable(a.overall, b.overall) || a.model.localeCompare(b.model)).map((row) => row.model);
 
 
806
  const colRanks = new Map();
807
  for (const [unit] of units) {
808
  const vals = state.models.map((model) => ({ model, value: matrix.get(model).get(unit) }));
@@ -817,9 +830,9 @@ function renderStrength() {
817
  for (const [, label] of units) html += `<th class="sp"><span>${label}</span></th>`;
818
  html += `</tr></thead><tbody>`;
819
  for (const model of overall) {
820
- const row = statsRows.find((r) => r.model === model);
821
- const ov = row.overall;
822
- html += `<tr class="${isExaone(model) ? "exaone-row" : ""}"><td class="mh">${displayName(model)}</td><td class="ov" style="background:${color(ov, overall.length)}">${fmt(ov, finite(ov) && ov % 1 ? 1 : 0)}</td>`;
823
  for (const [unit] of units) {
824
  const k = matrix.get(model).get(unit);
825
  const rank = colRanks.get(unit).get(model);
@@ -867,7 +880,7 @@ function renderGuide() {
867
  function showModelDetail(model) {
868
  if (!state.recordsReady) return;
869
  const stats = tierStats().find((r) => r.model === model);
870
- const units = [...new Map(includedRecords().filter((r) => r.model === model).map((r) => [r.unit, r.unit_label || r.unit])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
871
  const categoryByUnit = new Map(includedRecords().filter((r) => r.model === model).map((r) => [r.unit, r.category || ""]));
872
  const matrixByTier = Object.fromEntries(Object.keys(TIER_LABEL).map((tier) => [tier, unitK(tier).get(model)]));
873
  let html = `<p class="detail-k">Rank sum = <b>${fmt(stats.overall, finite(stats.overall) && stats.overall % 1 ? 1 : 0)}</b></p><table><thead><tr><th>Category</th><th>Detail Category</th><th class="num">Point</th><th class="num">Ranking</th><th class="num">Decision</th></tr></thead><tbody>`;
@@ -888,7 +901,7 @@ function showModelDetail(model) {
888
  function showTierDetail(model, tier) {
889
  if (!state.recordsReady) return;
890
  const matrix = unitK(tier).get(model);
891
- const units = [...new Map(includedRecords().filter((r) => r.model === model && r.tier === tier).map((r) => [r.unit, r.unit_label || r.unit])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
892
  const categoryByUnit = new Map(includedRecords().filter((r) => r.model === model && r.tier === tier).map((r) => [r.unit, r.category || ""]));
893
  let html = `<p class="detail-k">${TIER_SHORT[tier]} K = <b>${fmt(tierStats().find((r) => r.model === model)[`${ASPECT[tier]}_k`])}</b></p><table><thead><tr><th>Category</th><th>Detail Category</th><th class="num">K</th></tr></thead><tbody>`;
894
  for (const [unit, label] of units) {
@@ -917,7 +930,7 @@ function showMetricDetail(model, tier, unit) {
917
  || horizonOrder(aTarget) - horizonOrder(bTarget)
918
  || a.metric.localeCompare(b.metric);
919
  });
920
- const label = rows[0]?.unit_label || unit;
921
  const k = geometricMean(rows.map((r) => r.rank));
922
  let html = `<p class="detail-k">${TIER_SHORT[tier]} ยท ${label} K = <b>${fmt(k)}</b> ยท ${rows.length.toLocaleString()} cells</p>`;
923
  html += `<div class="period-card"><h3>Description for Date Codes</h3><div class="period-help"><span><b>D</b> Day</span><span><b>W</b> Week</span><span><b>M</b> Month</span><span><b>Q</b> Quarter</span><span><b>H</b> Half-year</span><span><b>Y</b> Year</span><span><b>B</b> Business</span><span><b>BD</b> Business-day</span></div></div>`;
 
39
  const $ = (id) => document.getElementById(id);
40
  const isExaone = (model) => model === "exaone-forecast" || model.startsWith("exaone-");
41
  const displayName = (model) => isExaone(model) ? "EXAONE Forecast Finance" : model;
42
+ const displayDetailLabel = (label) => {
43
+ const map = {
44
+ "Crypto Pair Close (Top 100)": "Crypto Pair Close",
45
+ "OHLCV Close": "Close"
46
+ };
47
+ return map[label] || label;
48
+ };
49
  const finite = (v) => Number.isFinite(v);
50
  const fmt = (v, digits = 2) => finite(v) ? v.toFixed(digits) : '<span class="skip">โ€”</span>';
51
  const fmtValue = (v) => {
 
284
  for (const row of state.records) {
285
  const group = `${row.scope || "Other"} ยท ${row.category || "Other"}`;
286
  if (!grouped.has(group)) grouped.set(group, new Map());
287
+ if (!grouped.get(group).has(row.detail_category)) grouped.get(group).set(row.detail_category, displayDetailLabel(row.detail_category));
288
  }
289
  return [...grouped.entries()].sort((a, b) => a[0].localeCompare(b[0]));
290
  }
 
629
  const tier = $("howto-tier").value || "tier1";
630
  const current = $("howto-detail").value;
631
  const details = [...new Set(state.records.filter((r) => r.model === model && r.tier === tier).map((r) => r.detail_category))].sort();
632
+ $("howto-detail").innerHTML = details.map((detail) => `<option value="${detail}">${displayDetailLabel(detail)}</option>`).join("");
633
  if (details.includes(current)) $("howto-detail").value = current;
634
  fillHowtoFrequencies();
635
  }
 
775
  && candidate.series_id === row.series_id
776
  && candidate.metric === row.metric;
777
  }).length;
778
+ html += `<tr><td title="${row.category || ""}">${displayDetailLabel(row.detail_category)}</td><td title="${row.frequency}">${freqCode(row.frequency)}</td><td title="${row.metric}">${parts.name} <span class="dir-arrow ${direction > 0 ? "up" : "down"}">${direction > 0 ? "โ†‘" : "โ†“"}</span></td><td>${parts.type}</td><td>${parts.target}</td><td class="num">${fmtValue(row.value)}</td><td class="num">${rankText(row.rank, total)}</td></tr>`;
779
  }
780
  html += `</tbody></table><p class="note">ํ˜„์žฌ ์™ผ์ชฝ Metric ยท Detail Category ยท Frequency ํ•„ํ„ฐ ์กฐ๊ฑด ์•ˆ์—์„œ ์ด ํ‰๊ท  ์…€์„ ๊ตฌ์„ฑํ•œ ์‹ค์ œ metric ๊ฐ’๊ณผ rank์ž…๋‹ˆ๋‹ค.</p>`;
781
  openDrawer(`${displayName(model)} ยท ${metricGroupLabel(metricGroup)}`, html);
 
806
  $("strength-body").innerHTML = '<p class="loading-note">์„ ํƒ๋œ ํ•„ํ„ฐ ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” cell์ด ์—†์Šต๋‹ˆ๋‹ค.</p>';
807
  return;
808
  }
809
+ const overallScores = new Map(state.models.map((model) => [
810
+ model,
811
+ geometricMean(scopedRecords.filter((row) => row.model === model).map((row) => row.rank))
812
+ ]));
813
+ const overallRanks = new Map(rankRows([...overallScores.entries()].map(([model, value]) => ({ model, value })), "value", -1).map((row) => [row.model, row.rank]));
814
+ const units = [...new Map(scopedRecords.map((r) => [r.unit, displayDetailLabel(r.unit_label || r.unit)])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
815
  const matrix = unitK(null, scopedRecords);
816
+ const overall = state.models
817
+ .filter((model) => finite(overallScores.get(model)))
818
+ .sort((a, b) => compareNullable(overallScores.get(a), overallScores.get(b)) || a.localeCompare(b));
819
  const colRanks = new Map();
820
  for (const [unit] of units) {
821
  const vals = state.models.map((model) => ({ model, value: matrix.get(model).get(unit) }));
 
830
  for (const [, label] of units) html += `<th class="sp"><span>${label}</span></th>`;
831
  html += `</tr></thead><tbody>`;
832
  for (const model of overall) {
833
+ const ov = overallScores.get(model);
834
+ const ovRank = overallRanks.get(model);
835
+ html += `<tr class="${isExaone(model) ? "exaone-row" : ""}"><td class="mh">${displayName(model)}</td><td class="ov" style="background:${color(ovRank, overall.length)}" title="Overall K geomean">${fmt(ov)}</td>`;
836
  for (const [unit] of units) {
837
  const k = matrix.get(model).get(unit);
838
  const rank = colRanks.get(unit).get(model);
 
880
  function showModelDetail(model) {
881
  if (!state.recordsReady) return;
882
  const stats = tierStats().find((r) => r.model === model);
883
+ const units = [...new Map(includedRecords().filter((r) => r.model === model).map((r) => [r.unit, displayDetailLabel(r.unit_label || r.unit)])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
884
  const categoryByUnit = new Map(includedRecords().filter((r) => r.model === model).map((r) => [r.unit, r.category || ""]));
885
  const matrixByTier = Object.fromEntries(Object.keys(TIER_LABEL).map((tier) => [tier, unitK(tier).get(model)]));
886
  let html = `<p class="detail-k">Rank sum = <b>${fmt(stats.overall, finite(stats.overall) && stats.overall % 1 ? 1 : 0)}</b></p><table><thead><tr><th>Category</th><th>Detail Category</th><th class="num">Point</th><th class="num">Ranking</th><th class="num">Decision</th></tr></thead><tbody>`;
 
901
  function showTierDetail(model, tier) {
902
  if (!state.recordsReady) return;
903
  const matrix = unitK(tier).get(model);
904
+ const units = [...new Map(includedRecords().filter((r) => r.model === model && r.tier === tier).map((r) => [r.unit, displayDetailLabel(r.unit_label || r.unit)])).entries()].sort((a, b) => a[1].localeCompare(b[1]));
905
  const categoryByUnit = new Map(includedRecords().filter((r) => r.model === model && r.tier === tier).map((r) => [r.unit, r.category || ""]));
906
  let html = `<p class="detail-k">${TIER_SHORT[tier]} K = <b>${fmt(tierStats().find((r) => r.model === model)[`${ASPECT[tier]}_k`])}</b></p><table><thead><tr><th>Category</th><th>Detail Category</th><th class="num">K</th></tr></thead><tbody>`;
907
  for (const [unit, label] of units) {
 
930
  || horizonOrder(aTarget) - horizonOrder(bTarget)
931
  || a.metric.localeCompare(b.metric);
932
  });
933
+ const label = displayDetailLabel(rows[0]?.unit_label || unit);
934
  const k = geometricMean(rows.map((r) => r.rank));
935
  let html = `<p class="detail-k">${TIER_SHORT[tier]} ยท ${label} K = <b>${fmt(k)}</b> ยท ${rows.length.toLocaleString()} cells</p>`;
936
  html += `<div class="period-card"><h3>Description for Date Codes</h3><div class="period-help"><span><b>D</b> Day</span><span><b>W</b> Week</span><span><b>M</b> Month</span><span><b>Q</b> Quarter</span><span><b>H</b> Half-year</span><span><b>Y</b> Year</span><span><b>B</b> Business</span><span><b>BD</b> Business-day</span></div></div>`;