"""Tests para confidence_interval_mean (IC de la media / diferencia de medias Welch). Importa el modulo hoja directamente (`confidence_interval_mean`) para no depender de que el paquete reexporte la funcion en su __init__ (lo integra el orquestador al cerrar el grupo). Los golden se calculan con scipy dentro del propio test para que sean robustos: la funcion bajo prueba debe coincidir con la referencia de scipy a ~1e-9. """ import math import numpy as np from scipy import stats from confidence_interval_mean import confidence_interval_mean def test_one_sample_golden_contra_scipy(): # mean=5.0, n=8. Este dataset tiene sd POBLACIONAL (ddof=0) exactamente 2.0, # pero la sd MUESTRAL (ddof=1, la que exige la spec y la que es correcta para # el IC de una media con la t) es sqrt(32/7) ~ 2.13809. El golden robusto se # calcula con scipy usando se con ddof=1, no con el atajo 2.0/sqrt(8). data = [2, 4, 4, 4, 5, 5, 7, 9] out = confidence_interval_mean(data, confidence=0.95) n = len(data) mean = float(np.mean(data)) sd = float(np.std(data, ddof=1)) # sample sd ~ 2.13809 se = sd / math.sqrt(n) lo, hi = stats.t.interval(0.95, df=n - 1, loc=mean, scale=se) assert abs(out["mean"] - 5.0) < 1e-9 assert abs(out["se"] - se) < 1e-12 assert out["df"] == 7.0 assert out["n"] == 8 assert out["confidence"] == 0.95 assert abs(out["ci_low"] - lo) < 1e-9 assert abs(out["ci_high"] - hi) < 1e-9 # Valores tabulados correctos para ddof=1 (no los 3.32793/6.67207 del # enunciado, que asumian erroneamente sd=2.0 / ddof=0). assert abs(out["ci_low"] - 3.21251) < 1e-3 assert abs(out["ci_high"] - 6.78749) < 1e-3 assert "note" not in out def test_one_sample_distinto_nivel_confianza(): data = [10.0, 12.0, 11.0, 13.0, 9.0, 14.0] out = confidence_interval_mean(data, confidence=0.99) n = len(data) mean = float(np.mean(data)) se = float(np.std(data, ddof=1)) / math.sqrt(n) lo, hi = stats.t.interval(0.99, df=n - 1, loc=mean, scale=se) assert abs(out["mean"] - mean) < 1e-12 assert abs(out["ci_low"] - lo) < 1e-9 assert abs(out["ci_high"] - hi) < 1e-9 assert out["df"] == float(n - 1) def test_welch_diferencia_golden_contra_scipy(): data = [23.0, 21.0, 25.0, 22.0, 24.0, 26.0] other = [18.0, 20.0, 17.0, 19.0, 21.0] conf = 0.95 out = confidence_interval_mean(data, other, confidence=conf) a = np.asarray(data, dtype=float) b = np.asarray(other, dtype=float) n1, n2 = a.size, b.size mean1, mean2 = float(a.mean()), float(b.mean()) diff = mean1 - mean2 se1 = float(a.std(ddof=1)) / math.sqrt(n1) se2 = float(b.std(ddof=1)) / math.sqrt(n2) se = math.sqrt(se1**2 + se2**2) df = (se1**2 + se2**2) ** 2 / (se1**4 / (n1 - 1) + se2**4 / (n2 - 1)) lo, hi = stats.t.interval(conf, df=df, loc=diff, scale=se) assert abs(out["mean"] - diff) < 1e-9 assert abs(out["mean"] - (mean1 - mean2)) < 1e-9 assert abs(out["se"] - se) < 1e-12 assert abs(out["df"] - df) < 1e-9 assert abs(out["ci_low"] - lo) < 1e-9 assert abs(out["ci_high"] - hi) < 1e-9 assert out["n1"] == n1 assert out["n2"] == n2 assert out["n"] == n1 + n2 assert "note" not in out def test_edge_un_solo_elemento_no_lanza_nan_note(): out = confidence_interval_mean([5], confidence=0.95) assert out["mean"] == 5.0 # la media si esta definida con n=1 assert math.isnan(out["se"]) assert math.isnan(out["ci_low"]) assert math.isnan(out["ci_high"]) assert math.isnan(out["df"]) assert out["n"] == 1 assert "note" in out def test_edge_lista_vacia_no_lanza_note(): out = confidence_interval_mean([], confidence=0.95) assert math.isnan(out["mean"]) assert math.isnan(out["ci_low"]) assert math.isnan(out["ci_high"]) assert math.isnan(out["se"]) assert out["n"] == 0 assert "note" in out def test_edge_varianza_cero_colapsa_al_punto(): out = confidence_interval_mean([3, 3, 3], confidence=0.95) assert out["mean"] == 3.0 assert out["se"] == 0.0 assert out["ci_low"] == 3.0 assert out["ci_high"] == 3.0 assert not math.isnan(out["ci_low"]) assert out["n"] == 3 assert "note" in out def test_edge_welch_muestra_vacia_no_lanza_note(): out = confidence_interval_mean([1.0, 2.0, 3.0], [], confidence=0.95) assert math.isnan(out["mean"]) assert math.isnan(out["ci_low"]) assert math.isnan(out["se"]) assert out["n1"] == 3 assert out["n2"] == 0 assert "note" in out def test_edge_welch_n1_uno_no_lanza_note(): out = confidence_interval_mean([5.0], [1.0, 2.0, 3.0], confidence=0.95) # La diferencia de medias si esta definida. assert abs(out["mean"] - (5.0 - 2.0)) < 1e-9 assert math.isnan(out["se"]) assert math.isnan(out["ci_low"]) assert math.isnan(out["df"]) assert "note" in out