File size: 1,336 Bytes
e5235fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"""Retention (spec §7): R = s / t and chance-corrected R_c = (s - c) / (t - c), per task and as means."""
from __future__ import annotations


def chance_for(task: str, chance: dict) -> float:
    return float(chance.get(task, chance.get("default", 0.0)))


def retention(student: dict[str, float], teacher: dict[str, float], chance: dict) -> dict:
    rows = {}
    for task in student:
        if task not in teacher:
            continue
        s, t, c = student[task], teacher[task], chance_for(task, chance)
        rows[task] = {"student": s, "teacher": t, "chance": c, "R": s / t if t else float("nan"),
                      "R_c": (s - c) / (t - c) if t != c else float("nan")}
    n = len(rows)
    mean = {"R": sum(r["R"] for r in rows.values()) / n, "R_c": sum(r["R_c"] for r in rows.values()) / n} if n else {}
    return {"tasks": rows, "mean": mean}


def markdown(ret: dict, title: str) -> str:
    lines = [f"## {title}", "", "| Task | Teacher | Student | R | R_c |", "|---|---:|---:|---:|---:|"]
    for task, r in ret["tasks"].items():
        lines.append(f"| {task} | {100 * r['teacher']:.1f} | {100 * r['student']:.1f} | {r['R']:.3f} | {r['R_c']:.3f} |")
    if ret["mean"]:
        lines.append(f"| **mean** | | | **{ret['mean']['R']:.3f}** | **{ret['mean']['R_c']:.3f}** |")
    return "\n".join(lines) + "\n"