Iti0210w101demo

Allikas: Lambda

Peidetud Markovi mudeli näide loengust

Parameetrid (ülemineku- ja emissioonitõenäosused) ja abifunktsioon valimi võtmiseks.

import random

prior = {
   "cheat" : 0.5,
   "fair" : 0.5
}

transition = {
   "cheat" : {"fair" : 0.2, "cheat" : 0.8},
   "fair" : {"fair" : 0.7, "cheat" : 0.3},
}

emission = {
    "fair" : { "1" : 1/6, "2" : 1/6,"3" : 1/6,"4" : 1/6,"5" : 1/6,"6" : 1/6},
    "cheat" : { "1" : 0, "2" : 0,"3" : 0,"4" : 0,"5" : 0.2,"6" : 0.8}
}

def sample(d):
    population = []
    weights = []
    for k, v in d.items():
        population.append(k)
        weights.append(v)
    return random.choices(population, weights=weights)[0]

Genereerime mudeliga juhusliku seeria.

X = []
E = []
for i in range(50):
    if i == 0:
        Xi = sample(prior)
        print("picking", Xi, "die")
    else:
        prev = X[-1]
        Xi = sample(transition[prev])
        if prev != Xi:
            print("swapping die to", Xi)
    Ei = sample(emission[Xi])
    print(Ei)
    X.append(Xi)
    E.append(Ei)

Edasi-tagasi sõnumite arvutamine ja normaliseerimine:

# let's use a tuple for distributions
#  { "fair": 0.6, "cheat": 0.4} ==>  (0.6, 0.4)

def forward(fw_prev, e_k):
    # returns distribution over X_{k+1}
    result = []
    for x_k in ["fair", "cheat"]:
        S = 0
        for i, x_prev in enumerate(["fair", "cheat"]):
            S += transition[x_prev][x_k] * fw_prev[i]
        result.append(S * emission[x_k][e_k])
    res_S = sum(result)
    return tuple([r/res_S for r in result])

def backward(b_next, e_next):
    result = []
    for x_k in ["fair", "cheat"]:
        S = 0
        for i, x_next in enumerate(["fair", "cheat"]):
            S += emission[x_next][e_next] * transition[x_k][x_next] * b_next[i]
        result.append(S)
    return tuple(result)

def normalize(vect):
    S = sum(vect)
    return tuple([v/S for v in vect])

Peidetud muutujate leidmine.

def smoothed_estimate(E, t=50):
    f_prev = (prior["fair"], prior["cheat"])
    f_X = []
    for k in range(t):
        f_k = forward(f_prev, E[k])
        f_X.append(f_k)
        f_prev = f_k

    b = (0.5, 0.5)
    smooth_X = []
    for k in range(t-1, -1, -1):
        smooth_X.append(normalize([f_X[k][0] * b[0], f_X[k][1] * b[1]]))
        b = backward(b, E[k])
    smooth_X.reverse()
    return smooth_X

s_X = smoothed_estimate(E)
for i in range(50):
    print(X[i], E[i], "cheat probability", s_X[i][1])

Tulemuse hindamine.

def evaluate(guess_X, real_X, threshold=0.7):
    TP = 0
    FN = 0
    FP = 0
    for i in range(len(guess_X)):
        if guess_X[i][1] > threshold:
            if real_X[i] == "cheat":
                TP += 1
            else:
                FP += 1
        else:
            if real_X[i] == "cheat":
                FN += 1

    print("")
    print("Cheating caught {:.0f}%".format((TP/(TP+FN))*100))
    print("False accusations {:.0f}%".format((FP/(TP+FP))*100))

evaluate(s_X, X)

EM-algoritmiga üleminekujaotuse leidmine.

transition_orig = transition
transition = {}
for x in ["fair", "cheat"]:
    p = random.random()
    transition[x] = {"fair": p, "cheat": 1-p}

from collections import defaultdict

def em(E, iters=100):
    for i in range(iters):
        expected_X = smoothed_estimate(E)
        virtual_t = {"fair" : defaultdict(float),
                  "cheat" : defaultdict(float)}
        virtual_N = {"fair" : 0.0, "cheat" : 0.0}
        for j in range(len(E)-1):
            virtual_N["fair"] += expected_X[j][0]
            virtual_t["fair"]["fair"] += expected_X[j][0] * expected_X[j+1][0]
            virtual_t["cheat"]["fair"] += expected_X[j][1] * expected_X[j+1][0]
        virtual_N["cheat"] = len(E) - 1 - virtual_N["fair"]
        for x in ["fair", "cheat"]:
            p = virtual_t[x]["fair"]/virtual_N[x]
            transition[x] = {"fair": p, "cheat": 1-p}
        print(transition)
    return expected_X

em_X = em(E, 20)
evaluate(em_X, X)