File size: 2,089 Bytes
3b0d6b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
from __future__ import annotations

import math
import random


def wilson_interval(successes: int, n: int, confidence: float = 0.95) -> tuple[float, float]:
    if n <= 0:
        return 0.0, 0.0
    z = 1.959963984540054
    phat = successes / n
    denom = 1 + z * z / n
    center = (phat + z * z / (2 * n)) / denom
    margin = z * math.sqrt((phat * (1 - phat) + z * z / (4 * n)) / n) / denom
    return max(0.0, center - margin), min(1.0, center + margin)


def bootstrap_ci(values: list[float], iterations: int = 2000, confidence: float = 0.95) -> tuple[float, float]:
    if not values:
        return 0.0, 0.0
    if len(values) == 1:
        return values[0], values[0]
    means = []
    for _ in range(iterations):
        sample = [random.choice(values) for _ in range(len(values))]
        means.append(sum(sample) / len(sample))
    means.sort()
    alpha = (1 - confidence) / 2
    lo_idx = max(0, int(alpha * len(means)))
    hi_idx = min(len(means) - 1, int((1 - alpha) * len(means)) - 1)
    return means[lo_idx], means[hi_idx]


def task_bootstrap_ci(task_values: list[float], iterations: int = 2000, confidence: float = 0.95) -> tuple[float, float]:
    return bootstrap_ci(task_values, iterations=iterations, confidence=confidence)


def paired_bootstrap_delta(
    left: list[float], right: list[float], iterations: int = 2000, confidence: float = 0.95
) -> dict:
    if not left or not right or len(left) != len(right):
        return {"delta": 0.0, "ci_low": 0.0, "ci_high": 0.0}
    deltas = []
    paired = list(zip(left, right))
    for _ in range(iterations):
        sample = [random.choice(paired) for _ in range(len(paired))]
        diffs = [l - r for l, r in sample]
        deltas.append(sum(diffs) / len(diffs))
    deltas.sort()
    alpha = (1 - confidence) / 2
    lo_idx = max(0, int(alpha * len(deltas)))
    hi_idx = min(len(deltas) - 1, int((1 - alpha) * len(deltas)) - 1)
    observed = sum(l - r for l, r in paired) / len(paired)
    return {
        "delta": observed,
        "ci_low": deltas[lo_idx],
        "ci_high": deltas[hi_idx],
    }