"""概率融合：python 05_ensemble.py，在开发块选权重并独立验收。"""
import math
from random import Random
from statistics import correlation

rng = Random(39)
sigmoid = lambda z: 1 / (1 + math.exp(-z))
def sample(prefix, count):
    y, a, b = {}, {}, {}
    for i in range(count):
        key = (prefix, i)
        z = rng.gauss(0, 1.4)
        common = rng.gauss(0, 0.4)
        y[key] = int(rng.random() < sigmoid(z))
        a[key] = sigmoid(z + common + rng.gauss(0, 0.85))
        b[key] = sigmoid(z + common + rng.gauss(0, 0.95))
    assert set(y) == set(a) == set(b)
    return [(y[k], a[k], b[k]) for k in sorted(y)]

def loss(rows, w):
    terms = []
    for y, a, b in rows:
        p = min(1-1e-12, max(1e-12, w*a + (1-w)*b))
        terms.append(-math.log(p if y else 1-p))
    return sum(terms) / len(terms)

dev, heldout = sample("dev", 400), sample("holdout", 400)
best = min((i/10 for i in range(11)), key=lambda w: loss(dev, w))
print("dev residual correlation:", round(correlation([a-y for y,a,b in dev], [b-y for y,a,b in dev]), 3))
for name, w in (("A", 1), ("B", 0), ("mean", 0.5), ("tuned on dev", best)):
    print(name, "weight A:", w, "dev:", round(loss(dev,w),4), "holdout:", round(loss(heldout,w),4))

