<jupyter_start><jupyter_text>算法 9.1（EM算法）- 测试数据：p155，例9.1<jupyter_code>import math

class Em(object):
    def __init__(self, epsilon0=0.001, epsilon1=0.001):
        self._epsilon0 = epsilon0
        self._epsilon1 = epsilon1
        self._max_iteration = 3
        self._nu = None
        self._pi = 0
        self._p = 0
        self._q = 0

        self._nus = []
        self._thetas = []
    @property
    def theta(self):
        return self._pi, self._p, self._q
    def train(self, y_train, pi, p, q):
        length = len(y_train)
        self._pi = pi
        self._p = p
        self._q = q
        self._thetas.append((pi, p, q))
        self._nu = [0]*length
        for i in range(self._max_iteration):
            # 【p156，公式9.5】
            for j in range(length):
                b = self._pi * math.pow(self._p, y_train[j]) * math.pow(1 - self._p, 1 - y_train[j])
                c = (1 - self._pi) * math.pow(self._q, y_train[j]) * math.pow(1 - self._q, 1 - y_train[j])
                self._nu[j] = b / (b + c)
            # 【p156，公式9.6】
            self._pi = 1. / length * sum(self._nu)
            # 【p156，公式9.7】
            self._p = sum([self._nu[k] * y_train[k] for k in range(length)]) / sum(self._nu)
            # 【p156，公式9.8】
            self._q = sum([(1 - self._nu[k]) * y_train[k] for k in range(length)]) \
                        / sum([(1 - self._nu[k]) for k in range(length)])
            self._thetas.append((self._pi, self._p, self._q))
            print((self._pi, self._p, self._q))
            if self.is_stop():
                print('满足停机条件，终止循环。%s of %s' % (i, self._max_iteration))
                break

    def is_stop(self):
        # 【p158，中部步骤（4）】停止条件，Q函数还没懂要怎么实现
        pi0, p0, q0 = self._thetas[-2]
        pi1, p1, q1 = self._thetas[-1]
        if all([pi1- pi0 < self._epsilon0, p1 - p0 < self._epsilon0, q1 - q0 < self._epsilon0]):
            return True
        return False
    def q_fun(self):
        # Q函数还没懂要怎么实现
        pass

x_train = [1, 1, 0, 1, 0, 0, 1, 0, 1, 1]
em = Em()
pi, p, q = (0.5, 0.5, 0.5)
print('设置初值：pi=%.2f，p=%.2f，q=%.2f' % (pi, p, q))
em.train(x_train, pi, p, q)
pi, p, q = (0.4, 0.6, 0.7)
print('设置初值：pi=%.2f，p=%.2f，q=%.2f' % (pi, p, q))
em.train(x_train, pi, p, q)<jupyter_output>设置初值：pi=0.50，p=0.50，q=0.50
(0.5, 0.6, 0.6)
(0.5, 0.6, 0.6)
满足停机条件，终止循环。1 of 3
设置初值：pi=0.40，p=0.60，q=0.70
(0.4064171122994653, 0.5368421052631579, 0.6432432432432431)
(0.40641711229946537, 0.536842105263158, 0.6432432432432431)
满足停机条件，终止循环。1 of 3
{'fraction_non_alphanumeric': 0.17602548785344485, 'fraction_numerical': 0.09518120270808443, 'mean_word_length': 1.9345794392523366, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '479942', 'license': 'MIT', 'n_tokens_mistral': 1247, 'n_tokens_neox': 1170, 'n_words': 214, 'path': 'statistical_learning_method/algorithm 9.1(EM algorithm).ipynb', 'repo_name': 'StudyExchange/CourseCode', 'size': '2511'}