# 机器学习作业题目4实验报告
## 题目 4：推断和采样 (20 points)

注：由于编程和实验的软件环境使用的是Jupyter Notebook，且为图方便，将代码和实验报告一起编写，以之实验报告中含有所有使用的代码，有些位置不合时宜，望见谅。

### 任务定义：
>邻居 John 或 Mary 在听到我家的警铃响时，可能会给我打电话，警铃响可能因为发生地震或强盗。Burglary、Earthquake、Alarm、JohnCalls、MaryCalls 的取值可以是 True 或 False。这 5 个随机变量构成的贝叶斯网络入下图所示。

>（1）试通过精确推断（例如，变量消去法）计算后验概率$P(Burglary|JohnCalls = true, MaryCalls = false)$，计算后验概率$P(Burglary, Earthquake|JohnCalls = true, MaryCalls = false)$。

>（2）试通过 Gibbs 抽样，生成近似其真实分布的 100 个样本。并分析如何判断预热期结束。

### 输入输出：
- （1）精确推断：
    - 输入：需要推断的变量表达式
    - 输出：后验概率
- （2）Gibbs抽样：
    - 输入：无（贝叶斯网络已知）
    - 输出：近似真实分布的100个样本

### 方法描述

#### 变量消去法

首先转换后验概率：
$\begin{cases}
P(B|J=T, M=F)
=\frac{P(B, J=T, M=F)}{P(J=T, M=F)}
\\
P(B, E|J=T, M=F)
=\frac{P(B, E, J=T, M=F)}{P(J=T, M=F)}
\end{cases}$

即：
$\begin{cases}
P(B=T|J=T, M=F)
=\frac{P(B=T, J=T, M=F)}{P(J=T, M=F)}
\\
P(B=F|J=T, M=F)
=\frac{P(B=F, E, J=T, M=F)}{P(J=T, M=F)}
\\
P(B=T, E=T|J=T, M=F)
=\frac{P(B=T, E=T, J=T, M=F)}{P(J=T, M=F)}
\\
P(B=T, E=F|J=T, M=F)
=\frac{P(B=T, E=F, J=T, M=F)}{P(J=T, M=F)}
\\
P(B=F, E=T|J=T, M=F)
=\frac{P(B=F, E=T, J=T, M=F)}{P(J=T, M=F)}
\\
P(B=F, E=F|J=T, M=F)
=\frac{P(B=F, E=F, J=T, M=F)}{P(J=T, M=F)}
\end{cases}$

$\begin{align}
P(J=T, M=F)&=[P(B=T)P(E=T)P(A=T|B=T, E=T)+P(B=T)P(E=F)P(A=T|B=T, E=F)
\\&+P(B=F)P(E=T)P(A=T|B=F, E=T)+P(B=F)P(E=F)P(A=T|B=F, E=F)]
\\&*P(J=T|A=T)P(M=F|A=T)
\\&+[P(B=T)P(E=T)P(A=F|B=T, E=T)+P(B=T)P(E=F)P(A=F|B=T, E=F)
\\&+P(B=F)P(E=T)P(A=F|B=F, E=T)+P(B=F)P(E=F)P(A=F|B=F, E=F)]
\\&*P(J=T|A=F)P(M=F|A=F)
\\&=[0.001*0.002*0.95+0.001*0.998*0.94+0.999*0.002*0.29+0.999*0.998*0.001]*0.9*0.3
\\&+[0.001*0.002*0.05+0.001*0.998*0.06+0.999*0.002*0.71+0.999*0.998*0.999]*0.05*0.99
\end{align}$

$\begin{align}
P(B=T, J=T, M=F)
&=P(B=T)[(P(E=T)P(A=T|B=T, E=T)+P(E=F)P(A=T|B=T, E=F))
\\&*P(J=T|A=T)P(M=F|A=T)
\\&+(P(E=T)P(A=F|B=T, E=T)+P(E=F)P(A=F|B=T, E=F))
\\&*P(J=T|A=F)P(M=F|A=F)]
\\&=0.001*[(0.002*0.95+0.998*0.94)*0.9*0.3+(0.002*0.05+0.998*0.06)*0.05*0.99]
\end{align}$

$\begin{align}
P(B=F, J=T, M=F)
&=P(B=F)[(P(E=T)P(A=T|B=F, E=T)+P(E=F)P(A=T|B=F, E=F))
\\&*P(J=T|A=T)P(M=F|A=T)
\\&+(P(E=T)P(A=F|B=F, E=T)+P(E=F)P(A=F|B=F, E=F))
\\&*P(J=T|A=F)P(M=F|A=F)]
\\&=0.999*[(0.002*0.29+0.998*0.001)*0.9*0.3+(0.002*0.71+0.998*0.999)*0.05*0.99]
\end{align}$

$\begin{align}
P(B=T, E=T, J=T, M=F)
&=P(B=T)P(E=T)[P(A=T|B=T, E=T)P(J=T|A=T)P(M=F|A=T)
\\&+P(A=F|B=T, E=T)P(J=T|A=F)P(M=F|A=F)]
\\&=0.001*0.002*[0.95*0.9*0.3+0.05*0.05*0.99]
\end{align}$

$\begin{align}
P(B=T, E=F, J=T, M=F)
&=P(B=T)P(E=F)[P(A=T|B=T, E=F)P(J=T|A=T)P(M=F|A=T)
\\&+P(A=F|B=T, E=F)P(J=T|A=F)P(M=F|A=F)]
\\&=0.001*0.998*[0.94*0.9*0.3+0.06*0.05*0.99]
\end{align}$

$\begin{align}
P(B=F, E=T, J=T, M=F)
&=P(B=F)P(E=T)[P(A=T|B=F, E=T)P(J=T|A=T)P(M=F|A=T)
\\&+P(A=F|B=F, E=T)P(J=T|A=F)P(M=F|A=F)]
\\&=0.999*0.002*[0.29*0.9*0.3+0.71*0.05*0.99]
\end{align}$

$\begin{align}
P(B=F, E=F, J=T, M=F)
&=P(B=F)P(E=F)[P(A=T|B=F, E=F)P(J=T|A=T)P(M=F|A=T)
\\&+P(A=F|B=F, E=F)P(J=T|A=F)P(M=F|A=F)]
\\&=0.999*0.998*[0.001*0.9*0.3+0.999*0.05*0.99]
\end{align}$

#### Gibbs抽样

首先，根据概率表达式写一个简单的函数，可以计算BEAJM五元组内任意取值时的概率P，缺点就是难以复用。（可跳过下面代码）

```python
# Calculate P with any params
def P(B=None, E=None, A=None, J=None, M=None):
    P_B = {True: 0.001, False: 0.999}
    P_E = {True: 0.002, False: 0.998}
    P_A_BE = {
        (True, True): {
            True: 0.95,
            False: 0.05
        },
        (True, False): {
            True: 0.94,
            False: 0.06
        },
        (False, True): {
            True: 0.29,
            False: 0.71
        },
        (False, False): {
            True: 0.001,
            False: 0.999
        }
    }
    P_J_A = {True: {True: 0.9, False: 0.1}, False: {True: 0.05, False: 0.95}}
    P_M_A = {True: {True: 0.7, False: 0.3}, False: {True: 0.01, False: 0.99}}

    P = 1
    if B is not None:
        P *= P_B[B]
    if E is not None:
        P *= P_E[E]

    if A is not None or J is not None or M is not None:
        if B is not None and E is not None:
            P_AT = P_A_BE[(B, E)][True]
            P_AF = P_A_BE[(B, E)][False]
        elif B is not None and E is None:
            P_AT = P_E[True] * P_A_BE[(B, True)][True] + P_E[False] * P_A_BE[
                (B, False)][True]
            P_AF = P_E[True] * P_A_BE[(B, True)][False] + P_E[False] * P_A_BE[
                (B, False)][False]
        elif B is None and E is not None:
            P_AT = P_B[True] * P_A_BE[(True, E)][True] + P_B[False] * P_A_BE[
                (False, E)][True]
            P_AF = P_B[True] * P_A_BE[(True, E)][False] + P_B[False] * P_A_BE[
                (False, E)][False]
        else:
            P_AT = P_B[True] * P_E[True] * P_A_BE[
                (True, True)][True] + P_B[True] * P_E[False] * P_A_BE[
                    (True, False)][True] + P_B[False] * P_E[True] * P_A_BE[(
                        False, True)][True] + P_B[False] * P_E[False] * P_A_BE[
                            (False, False)][True]
            P_AF = P_B[True] * P_E[True] * P_A_BE[
                (True, True)][False] + P_B[True] * P_E[False] * P_A_BE[
                    (True, False)][False] + P_B[False] * P_E[True] * P_A_BE[
                        (False,
                         True)][False] + P_B[False] * P_E[False] * P_A_BE[
                             (False, False)][False]

        P_A = {True: P_AT, False: P_AF}

        if A is not None and J is None and M is None:
            P_A = {A: P_A[A], not A: 0}

        if J is not None:
            if A is not None:
                P_JT = P_A[A] * P_J_A[A][J]
                P_A = {A: P_JT, not A: 0}
            else:
                P_JT = P_A[True] * P_J_A[True][J]
                P_JF = P_A[False] * P_J_A[False][J]
                P_A = {True: P_JT, False: P_JF}
        if M is not None:
            if A is not None:
                P_MT = P_A[A] * P_M_A[A][M]
                P_A = {A: P_MT, not A: 0}
            else:
                P_MT = P_A[True] * P_M_A[True][M]
                P_MF = P_A[False] * P_M_A[False][M]
                P_A = {True: P_MT, False: P_MF}

        P *= P_A[True] + P_A[False]

    return P
```

然后，再设计函数GibbsSampling，输入初始状态和抽取样本数量t，然后运行Gibbs迭代，在BEAJM中第一次出现True（突变）后开始采样100次。（可跳过下面代码）

```python
# Import numpy as np and matplotlib as plt
%pylab inline

def GibbsSampling(x=[False, False, False, False, False], t=100):

    samples = []
    flag = False

    while True:
        rands = np.random.rand(5)

        # B
        Q_B = P(x[0], x[1], x[2], x[3], x[4]) / P(
            E=x[1], A=x[2], J=x[3], M=x[4])
        if rands[0] > Q_B:
            x[0] = not x[0]  #B

        Q_E = P(x[0], x[1], x[2], x[3], x[4]) / P(
            B=x[0], A=x[2], J=x[3], M=x[4])
        if rands[1] > Q_E:
            x[1] = not x[1]  # E

        Q_A = P(x[0], x[1], x[2], x[3], x[4]) / P(
            B=x[0], E=x[1], J=x[3], M=x[4])
        if rands[2] > Q_A:
            x[2] = not x[2]  # A

        Q_J = P(x[0], x[1], x[2], x[3], x[4]) / P(
            B=x[0], E=x[1], A=x[2], M=x[4])
        if rands[3] > Q_J:
            x[3] = not x[3]  # J

        Q_M = P(x[0], x[1], x[2], x[3], x[4]) / P(
            B=x[0], E=x[1], A=x[2], J=x[3])
        if rands[4] > Q_M:
            x[4] = not x[4]  # M

        if True in x:
            flag = True
        if flag:
            samples.append(np.array(x))
            if len(samples) == t:
                break
    return np.asarray(samples)
```

    Populating the interactive namespace from numpy and matplotlib

### 结果分析（性能评价）

#### 变量消去法

根据之前的概率公式算出如下结果：

```python
P_JTMF = (0.001 * 0.002 * 0.95 + 0.001 * 0.998 * 0.94 + 0.999 * 0.002 * 0.29 +
          0.999 * 0.998 * 0.001) * 0.9 * 0.3 + (
              0.001 * 0.002 * 0.05 + 0.001 * 0.998 * 0.06 +
              0.999 * 0.002 * 0.71 + 0.999 * 0.998 * 0.999) * 0.05 * 0.99
P_BTJTMF = 0.001 * ((0.002 * 0.95 + 0.998 * 0.94) * 0.9 * 0.3 +
                    (0.002 * 0.05 + 0.998 * 0.06) * 0.05 * 0.99)
P_BFJTMF = 0.999 * ((0.002 * 0.29 + 0.998 * 0.001) * 0.9 * 0.3 +
                    (0.002 * 0.71 + 0.998 * 0.999) * 0.05 * 0.99)
P_BTETJTMF = 0.001 * 0.002 * (0.95 * 0.9 * 0.3 + 0.05 * 0.05 * 0.99)
P_BTEFJTMF = 0.001 * 0.998 * (0.94 * 0.9 * 0.3 + 0.06 * 0.05 * 0.99)
P_BFETJTMF = 0.999 * 0.002 * (0.29 * 0.9 * 0.3 + 0.71 * 0.05 * 0.99)
P_BFEFJTMF = 0.999 * 0.998 * (0.001 * 0.9 * 0.3 + 0.999 * 0.05 * 0.99)

P1_T = P_BTJTMF / P_JTMF
P1_F = P_BFJTMF / P_JTMF
P2_TT = P_BTETJTMF / P_JTMF
P2_TF = P_BTEFJTMF / P_JTMF
P2_FT = P_BFETJTMF / P_JTMF
P2_FF = P_BFEFJTMF / P_JTMF

print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" + format(P1_T, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P1_F, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_TT, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_TF, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_FT, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_FF, '.9f'))
```

    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.005129858
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.994870142
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.000010348
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.005119510
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.004528292
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.990341850

经过下列验算，2组概率和为1，证明变量消去法计算无误。

```python
print(
    "𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)+𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)="
    + format(P1_T + P1_F, '.9f'))

print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)")
print("+𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)")
print("+𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)")
print("+𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)=" +
      format(P2_TT + P2_TF + P2_FT + P2_FF, '.9f'))
```

    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)+𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)=1.000000000
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)
    +𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)
    +𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)
    +𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)=1.000000000

补充：再使用Gibbs采样中设计的P函数重新计算一遍，证明变量消去法计算无误且P函数能正确计算

```python
P_JTMF_2 = P(J=True, M=False)
P_BTJTMF_2 = P(B=True, J=True, M=False)
P_BFJTMF_2 = P(B=False, J=True, M=False)
P_BTETJTMF_2 = P(B=True, E=True, J=True, M=False)
P_BTEFJTMF_2 = P(B=True, E=False, J=True, M=False)
P_BFETJTMF_2 = P(B=False, E=True, J=True, M=False)
P_BFEFJTMF_2 = P(B=False, E=False, J=True, M=False)

P1_T_2 = P_BTJTMF_2 / P_JTMF_2
P1_F_2 = P_BFJTMF_2 / P_JTMF_2
P2_TT_2 = P_BTETJTMF_2 / P_JTMF_2
P2_TF_2 = P_BTEFJTMF_2 / P_JTMF_2
P2_FT_2 = P_BFETJTMF_2 / P_JTMF_2
P2_FF_2 = P_BFEFJTMF_2 / P_JTMF_2

print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P1_T_2, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P1_F_2, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_TT_2, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_TF_2, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_FT_2, '.9f'))
print("𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈" +
      format(P2_FF_2, '.9f'))
```

    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.005129858
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.994870142
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.000010348
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑡𝑟𝑢𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.005119510
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑡𝑟𝑢𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.004528292
    𝑃(𝐵𝑢𝑟𝑔𝑙𝑎𝑟𝑦=𝑓𝑎𝑙𝑠𝑒,𝐸𝑎𝑟𝑡ℎ𝑞𝑢𝑎𝑘𝑒=𝑓𝑎𝑙𝑠𝑒|𝐽𝑜ℎ𝑛𝐶𝑎𝑙𝑙𝑠=𝑡𝑟𝑢𝑒,𝑀𝑎𝑟𝑦𝐶𝑎𝑙𝑙𝑠=𝑓𝑎𝑙𝑠𝑒)≈0.990341850

#### Gibbs抽样

以下是BEAJM各自独立的概率期望，用于评估采集的样本是否在和理想情况相似（可以同时看出P(True)+P(False)==1，函数P没有计算问题）

```python
print(P(B=True), P(B=False))
print(P(E=True), P(E=False))
print(P(A=True), P(A=False))
print(P(J=True), P(J=False))
print(P(M=True), P(M=False))
```

    0.001 0.999
    0.002 0.998
    0.002516442 0.997483558
    0.052138975700000006 0.9478610243
    0.01173634498 0.98826365502

采集100个样本，因为概率过低的原因，B、E、A通常为0，J在0.05范围附近波动，M在0.01范围波动，和上面计算出的概率期望相近似

```python
samples = GibbsSampling()
for i in range(5):
    print(np.average(samples[:, i]))
```

    0.0
    0.0
    0.0
    0.05
    0.01

生成近似其真实分布的 100 个样本，如下（可跳过）

```python
samples
```

    array([[False, False, False,  True, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False,  True, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False,  True],
           [False, False, False, False, False],
           [False, False, False,  True, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False,  True, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False,  True, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False],
           [False, False, False, False, False]])

再采集100000个样本，可以看出BEAJM的独立概率期望和上面计算出的概率期望更加近似且稳定

```python
samples_big = GibbsSampling(t=100000)
for i in range(5):
    print(np.average(samples_big[:, i]))
```

    0.00094
    0.002
    0.00241
    0.05306
    0.01138

结论：事件概率都很低的情况且采集样本过小的情况下，可以简单的以冰冻期（全为概率最高的False）作为初始参数，以破冰时刻（任意事件为True）作为预热期何时结束，即可采集到近似其真实分布的 100 个样本。如果认为有偏差，也可以在破冰时刻后开始采集大量的样本（远大于所需样本），之后再从大量样本中随机抽取所需数量的样本，也可以保证采集的样本近似其真实分布。

### 编程和实验的软硬件环境
- 软件环境
    - OS：Windows 10
    - IDE：PyCharm Professional + Jupyter Notebook
    - Python：3.7
- 硬件环境
    - CPU：Intel(R) Core(TM) i7-9750H


# Earliness

The differences in performance with respect to earliness, is measured using mean absolute error over the first \textit{k} prefixes, across methods and data-sets. In other words, every \textit{t'th} event is evaluated independently of all prior or subsequent events in its trace.

\begin{equation}MAE_{t} = \frac{1}{N}\sum_{i=1}^{N}\mid y_{t}^i - \hat{y}_{t}^i\mid\end{equation}

Here, \textit{t} is the prefix or event number in each trace, and \textit{i} is the trace in the test period. This approach have been used in similar literature on both remaining time prediction, as well as classification problems with data in prefix-log format \cite{NiekTax2017,Verenich2019,Camargo2019,Teinemaa2018}. Since there is a difference in number of prefixes generated from each of the datasets (due to truncation), the same \textit{k} is used for the comparison of differences.

Due to the nature of the prefix log format, the support of the distribution of prefixes is skewed towards the lowest prefix indexes $t$. However, as \textit{business objective B} is not directed towards traces with low support, no form of normalization is applied across different prefixes in the earliness evaluation. Significance of the results are evaluated through ANOVA test.

```python

```

```python
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
#sns.set_theme(style="whitegrid")
sns.set(rc={'figure.figsize':(16,8)})

experiments = pd.read_csv("../Experiments.csv")

# filter out unfinished experiments
experiments = experiments.loc[experiments.Done == 1]

"""
Filter below needs to be removed!!
"""

# look at only one dataset (initial analysis)
#experiments = experiments.loc[experiments.F_dataset == 0.0]

experiments.head(50)
```

      F_lossfunction
      F_transform
      F_gamma
      F_beta
      F_alpha
      F_dataset
      F_max_epochs
      F_learningrate
      F_batch_size
      F_optimizer
      ...
      num_epochs
      loss_slope
      val_loss_slope
      Done
      AE_1
      AE_2
      AE_3
      AE_4
      AE_5
      Name_fix

      0
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      12
      -0.360898
      -0.121376
      1
      12.273245
      12.269328
      12.582674
      12.573682
      13.206407
      1

      1
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      11
      -0.543476
      -0.311670
      1
      13.135334
      13.089668
      13.346655
      13.163195
      13.632847
      1

      2
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      18
      -0.156760
      -0.164706
      1
      12.448204
      12.448030
      12.725984
      12.726715
      13.285806
      1

      3
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      10
      -0.416395
      0.366206
      1
      18.804447
      18.875558
      18.833176
      18.985951
      18.985893
      1

      4
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      10
      -0.368649
      -0.093126
      1
      12.489663
      12.488502
      12.762201
      12.757728
      13.307211
      1

      5
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      6
      -1.140618
      1.827061
      1
      12.901717
      12.896110
      13.399539
      13.394462
      14.431701
      1

      6
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      10
      -0.429650
      -0.159592
      1
      12.433382
      12.433291
      12.713015
      12.714218
      13.277138
      1

      7
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      21
      -0.106672
      -0.045832
      1
      12.532833
      12.532936
      12.800509
      12.801363
      13.339163
      1

      8
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      14
      -0.252325
      -0.104971
      1
      12.642923
      12.643144
      12.898908
      12.899986
      13.413662
      1

      9
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      10
      -0.521990
      -0.115505
      1
      12.399788
      12.401073
      12.684325
      12.691315
      13.263359
      1

      10
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      20
      -0.103358
      -0.011682
      1
      12.504563
      12.503287
      12.775217
      12.752700
      13.255245
      1

      11
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      10
      -0.455079
      -0.385454
      1
      12.226658
      12.224564
      12.582572
      12.582188
      13.309889
      1

      12
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      17
      -0.171259
      -0.058339
      1
      12.581450
      12.583925
      12.843725
      12.851311
      13.375418
      1

      13
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      25
      -0.099670
      -0.075927
      1
      12.511874
      12.511771
      12.781713
      12.782580
      13.325282
      1

      14
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      17
      -0.128738
      -0.010340
      1
      12.994051
      12.994650
      13.217722
      13.217973
      13.664245
      1

      15
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      16
      -0.208582
      -0.070162
      1
      12.573292
      12.573395
      12.836473
      12.837341
      13.365999
      1

      16
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      25
      -0.102024
      -0.059729
      1
      12.507104
      12.506974
      12.777489
      12.778312
      13.322182
      1

      17
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      12
      -0.289949
      -0.081872
      1
      12.541120
      12.540719
      12.807875
      12.811778
      13.348699
      1

      18
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      9
      -0.536275
      -0.226781
      1
      12.418341
      12.552613
      12.836774
      13.788663
      14.374054
      1

      19
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      14
      -0.225430
      -0.092752
      1
      12.506020
      12.505782
      12.776510
      12.776807
      13.314516
      1

      20
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      15
      -0.278633
      -0.213003
      1
      12.649412
      12.649851
      12.904733
      12.906689
      13.418812
      1

      21
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      9
      -0.394390
      -0.083854
      1
      12.478084
      12.478664
      12.752086
      12.768040
      13.315178
      1

      22
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      13
      -0.369295
      -0.206269
      1
      12.567806
      12.567909
      12.831597
      12.832465
      13.362370
      1

      23
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      9
      -0.461681
      -0.002685
      1
      12.237081
      12.234477
      12.561365
      12.553891
      13.217430
      1

      24
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      23
      -0.113246
      -0.066275
      1
      12.378390
      12.377979
      12.666180
      12.666313
      13.246416
      1

      25
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      14
      -0.290295
      -0.113923
      1
      12.466578
      12.466390
      12.742035
      12.742713
      13.297071
      1

      26
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      11
      -0.279593
      -0.088365
      1
      12.507994
      12.505562
      12.778271
      12.775628
      13.321465
      1

      27
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      6
      -0.807006
      3.012454
      1
      12.497630
      12.493317
      12.930566
      12.926484
      13.828131
      1

      28
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      9
      -0.656962
      -0.334209
      1
      12.546885
      12.541888
      12.813000
      12.813888
      13.361069
      1

      29
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      20
      -0.129536
      -0.038939
      1
      12.845728
      12.846532
      13.082581
      13.084027
      13.557435
      1

      30
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      16
      -0.153792
      -0.036745
      1
      12.497829
      12.498622
      12.769335
      12.771998
      13.317356
      1

      31
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      14
      -0.229943
      -0.039614
      1
      12.445335
      12.445162
      12.723478
      12.724212
      13.284046
      1

      32
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      16
      -0.229741
      -0.206242
      1
      12.522193
      12.522046
      12.791051
      12.790878
      13.331324
      1

      33
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      8
      -0.645957
      -0.102111
      1
      14.012884
      14.016686
      14.169872
      14.179500
      14.484947
      1

      34
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      18
      -0.114417
      -0.046773
      1
      12.482971
      12.481229
      12.756355
      12.736321
      13.289619
      1

      35
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      12
      -0.264112
      -0.140317
      1
      12.354540
      12.354100
      12.645905
      12.645917
      13.234123
      1

      36
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      9
      -0.732703
      -0.083157
      1
      14.963756
      14.970586
      15.084392
      15.172527
      15.399037
      1

      37
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      19
      -0.091814
      -0.018850
      1
      12.656666
      12.656887
      12.911245
      12.912323
      13.423122
      1

      38
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      6
      -0.752056
      0.065772
      1
      13.470663
      13.472735
      13.657550
      13.665105
      14.032482
      1

      39
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      13
      -0.370626
      -0.264241
      1
      12.228890
      12.232136
      12.588635
      12.604847
      13.337741
      1

      40
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      11
      -0.362057
      -0.081666
      1
      13.625469
      13.627599
      13.802152
      13.807916
      14.155142
      1

      41
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      19
      -0.133744
      -0.030262
      1
      12.464993
      12.464821
      12.740651
      12.741388
      13.296134
      1

      42
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      19
      -0.119085
      -0.037943
      1
      12.478665
      12.478491
      12.752594
      12.753324
      13.304535
      1

      43
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      6
      -0.777883
      0.658282
      1
      13.117696
      13.112789
      13.647113
      13.643524
      14.744209
      1

      44
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      11
      -0.294225
      -0.040309
      1
      12.518045
      12.518082
      12.787306
      12.788122
      13.329345
      1

      45
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      7
      -0.782478
      0.034687
      1
      12.241309
      12.240201
      12.563407
      12.562708
      13.219796
      1

      46
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      8
      -0.534648
      -0.040991
      1
      12.629777
      12.630042
      12.887107
      12.888379
      13.404763
      1

      47
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      17
      -0.166633
      -0.067023
      1
      13.086525
      13.087375
      13.302112
      13.303360
      13.732835
      1

      48
      MAE
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      18
      -0.096453
      0.001098
      1
      12.748744
      12.749629
      12.994759
      12.996315
      13.489837
      1

      49
      MAE_td
      0.0
      0.0
      1.0
      1.0
      Sepsis
      200.0
      0.1
      2048.0
      0.0
      ...
      14
      -0.281839
      -0.089152
      1
      13.002739
      13.003592
      13.225651
      13.227015
      13.671477
      1

50 rows × 27 columns

```python
results = []

# go trough all experiments
for exp in set(experiments.RUN):

    # get experiment results
    experiment_i = experiments.loc[experiments.RUN == exp]

    # get inference table
    inference_test = pd.read_csv("../experiments/"+str(exp)+"/inference_tables/Inf_test.csv")

    ########## process the results #####################

    #placeholders
    event_numbers = []
    #num_of_events = []
    event_mae = []
    event_mae_normalized = []

    for prefix in set(inference_test.event_number):

        mae_prefix = np.mean(inference_test.loc[inference_test.event_number == prefix].AE)/60/60/24

        #get average duration per prefix
        avg_duration = np.mean(inference_test.loc[inference_test.event_number == prefix].caseduration_days)

        mae_prefix_normalized = mae_prefix/avg_duration

        num_events = inference_test.loc[inference_test.event_number == prefix].num_events

        event_numbers.append(prefix)
        event_mae_normalized.append(mae_prefix_normalized)
        event_mae.append(mae_prefix)

    # Collect experiment results
    results_i = pd.DataFrame({"event_number":event_numbers,
                              "event_mae_normalized":event_mae_normalized,
                              "event_mae":event_mae})

    for column in experiment_i.columns:
        results_i[column] = experiment_i.loc[experiment_i.index[0]][column]

    results.append(results_i)

#Create df
results = pd.concat(results)
```

```python
results.columns
```

    Index(['event_number', 'event_mae_normalized', 'event_mae', 'F_lossfunction',
           'F_transform', 'F_gamma', 'F_beta', 'F_alpha', 'F_dataset',
           'F_max_epochs', 'F_learningrate', 'F_batch_size', 'F_optimizer',
           'F_earlystop_steps', 'F_experiment', 'Notes', 'DOE', 'Duration_sec',
           'MAE', 'RUN', 'num_epochs', 'loss_slope', 'val_loss_slope', 'Done',
           'AE_1', 'AE_2', 'AE_3', 'AE_4', 'AE_5', 'Name_fix'],
          dtype='object')

```python
#Save results
results.to_csv("../Earliness_results.csv",index=False)
```

## Inspect a single dataset

```python
#Quick inspection of single dataset
dataset = ["Sepsis","helpdesk","traffic_fines","hospital_billing"][0]

"""
Look at only log-transformed models:
"""

max_num_events = 10

results_sub = results.loc[results.F_transform == 0]
results_sub = results_sub.loc[results_sub.F_max_epochs == 200]
results_sub = results_sub.loc[results_sub.F_dataset == dataset]

results_sub = results_sub.loc[results_sub.event_number < max_num_events+1]
results_sub = results_sub.loc[results_sub.event_mae < 30]
print("Num runs: ",str(len(results_sub.RUN.unique())))

#betas = results_sub.F_beta.unique()
#print(betas)
#results_sub = results_sub.loc[results_sub.F_beta > 0.5]

alphas = results_sub.F_alpha.unique()
print(alphas)
#results_sub = results_sub.loc[results_sub.F_alpha == alphas[5]]
#results_sub = results_sub.loc[results_sub.F_alpha == 1]

ax = sns.boxplot(x="event_number", y="event_mae", hue="F_lossfunction",
                 data=results_sub)#,fliersize=0.0)
ax.set_title(dataset)
```

```python
import statsmodels.api as sm
from statsmodels.formula.api import ols
import statsmodels

# Subset results
results_sub = results.loc[results.event_number < max_num_events+1]
#results_sub = results_sub.loc[results_sub.event_mae < 25]

table = results_sub

#for loss in results_sub.F_lossfunction.unique():
#    print("\n\nLOSS: "+str(loss)+"\n\n")

alphas = results_sub.F_alpha.unique()
print(alphas)

for alpha in alphas:

    testdata = results_sub.loc[results_sub.F_alpha==alpha]

    #specify loss name
    baseline = "MAE"

    d1 = testdata.loc[testdata.F_lossfunction==baseline].event_mae.values

    #specify loss name
    comparison = "MAE_td"

    d2 = testdata.loc[testdata.F_lossfunction==comparison]#.MAE.values

    #further specify subset
    d2 = d2.event_mae.values

    out = statsmodels.stats.weightstats.CompareMeans.from_data(d1, d2).summary(use_t=True, alpha=0.05, usevar='pooled')

    print("DATA: "+ dataset)
    print("DATA: "+ str(alpha))
    print("MAE:     "+ str(np.mean(d1)))
    print(str(comparison)+":  "+ str(np.mean(d2)))
    print(out)
```

    [1.]
    DATA: Sepsis
    DATA: 1.0
    MAE:     13.615669619611454
    MAE_td:  14.032059767295534
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4164      0.105     -3.948      0.000      -0.624      -0.209
    ==============================================================================

```python
import statsmodels.api as sm
from statsmodels.formula.api import ols
import statsmodels

# Subset results
results_sub = results.loc[results.event_number < max_num_events+1]
#results_sub = results_sub.loc[results_sub.event_mae < 25]

table = results_sub

#for loss in results_sub.F_lossfunction.unique():
#    print("\n\nLOSS: "+str(loss)+"\n\n")

alphas = results_sub.F_alpha.unique()
print(alphas)

alpha = alphas[0]

for evno in list(range(1,max_num_events)):

    testdata = results_sub.loc[results_sub.event_number == evno]

    testdata = testdata.loc[testdata.F_alpha==alpha]

    #specify loss name
    baseline = "MAE"

    d1 = testdata.loc[testdata.F_lossfunction==baseline].event_mae.values

    #specify loss name
    comparison = "MAE_td"

    d2 = testdata.loc[testdata.F_lossfunction==comparison]#.MAE.values

    #further specify subset
    d2 = d2.event_mae.values

    out = statsmodels.stats.weightstats.CompareMeans.from_data(d1, d2).summary(use_t=True, alpha=0.05, usevar='pooled')

    print("DATA: "+ dataset)
    print("Alpha: "+ str(alpha))
    print("Event: "+ str(evno))
    print("MAE:     "+ str(np.mean(d1)))
    print(str(comparison)+":  "+ str(np.mean(d2)))
    print(out)
```

    [1.]
    DATA: Sepsis
    Alpha: 1.0
    Event: 1
    MAE:     12.733033807260828
    MAE_td:  13.124612095603363
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.3916      0.314     -1.246      0.218      -1.021       0.237
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 2
    MAE:     12.737798413113103
    MAE_td:  13.125374401258474
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.3876      0.316     -1.227      0.225      -1.020       0.245
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 3
    MAE:     12.990656339395233
    MAE_td:  13.393653813310856
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4030      0.300     -1.344      0.184      -1.003       0.197
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 4
    MAE:     13.025724011073008
    MAE_td:  13.394582033453121
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.3689      0.305     -1.209      0.232      -0.980       0.242
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 5
    MAE:     13.53293496867119
    MAE_td:  13.93527202954153
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4023      0.278     -1.448      0.153      -0.959       0.154
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 6
    MAE:     13.83549940460292
    MAE_td:  14.27842671924771
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4429      0.260     -1.705      0.093      -0.963       0.077
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 7
    MAE:     13.833348875741278
    MAE_td:  14.275408691748055
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4421      0.271     -1.630      0.108      -0.985       0.101
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 8
    MAE:     14.536975417046165
    MAE_td:  14.98372107281241
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4467      0.246     -1.816      0.074      -0.939       0.046
    ==============================================================================
    DATA: Sepsis
    Alpha: 1.0
    Event: 9
    MAE:     14.139331361800908
    MAE_td:  14.55770482557006
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1     -0.4184      0.264     -1.583      0.119      -0.947       0.111
    ==============================================================================

```python
alpha = alphas[0]
plotdata = results_sub.loc[results_sub.F_alpha==alpha]

ax = sns.boxplot(x="event_number", y="event_mae_normalized", hue="F_lossfunction",
                 data=plotdata)#,fliersize=0.0)
ax.set_title(dataset+", Alpha = "+str(alpha))
#ax.set_ylabel(target)
```

```python
table = pd.pivot_table(results_sub,
                       values='event_mae_normalized', index=['F_lossfunction','F_alpha'],
                    columns=['event_number'], aggfunc=np.mean)
table
```

      event_number
      1
      2
      3
      4
      5
      6
      7
      8
      9

      F_lossfunction
      F_alpha

      MAE
      1.0
      0.49320
      0.256113
      0.274370
      0.705503
      0.653811
      0.570428
      0.445933
      0.538072
      1.024955

      MAE_td
      1.0
      0.50707
      0.249815
      0.251501
      0.704614
      0.645678
      0.581853
      0.442242
      0.518662
      1.026022

```python
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_theme()

# Load the example flights dataset and convert to long-form
flights_long = sns.load_dataset("flights")
flights = flights_long.pivot("month", "year", "passengers")

# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(16, 12))

cmap = sns.cm.rocket_r
sns.heatmap(table,
            cmap=cmap,
            annot=True,
            #fmt="d",
            linewidths=.5,
            ax=ax)
```

```python

```

# Normalized comparison

```python
results = pd.read_csv("../Earliness_results.csv")
results.head(120)
```

      event_number
      event_mae_normalized
      event_mae
      F_transform
      F_gamma
      F_beta
      F_alpha
      F_dataset
      F_max_epochs
      F_experiment
      Notes
      DOE
      Duration_sec
      MAE
      RUN
      Done

      0
      1
      0.922724
      13.543839
      0.0
      1.0
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      216.170466
      15.473099
      1
      1

      1
      2
      0.922328
      13.538031
      0.0
      1.0
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      216.170466
      15.473099
      1
      1

      2
      3
      0.921436
      14.131433
      0.0
      1.0
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      216.170466
      15.473099
      1
      1

      3
      4
      0.921121
      14.126614
      0.0
      1.0
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      216.170466
      15.473099
      1
      1

      4
      5
      0.919967
      15.347748
      0.0
      1.0
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      216.170466
      15.473099
      1
      1

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      115
      4
      0.923331
      14.160498
      0.0
      0.5
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      206.296323
      15.517496
      5
      1

      116
      5
      0.922465
      15.389415
      0.0
      0.5
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      206.296323
      15.517496
      5
      1

      117
      6
      0.921350
      16.159066
      0.0
      0.5
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      206.296323
      15.517496
      5
      1

      118
      7
      0.914754
      16.126082
      0.0
      0.5
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      206.296323
      15.517496
      5
      1

      119
      8
      0.906422
      17.592821
      0.0
      0.5
      0.2
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      206.296323
      15.517496
      5
      1

120 rows × 16 columns

```python
results.F_lossfunction.value_counts()
```

    MAE       800
    MAE_td    800
    Name: F_lossfunction, dtype: int64

```python
import seaborn as sns, matplotlib.pyplot as plt
#sns.set(style="whitegrid")

data = results.loc[results.event_number< 6]

ordered_data = sorted(data['F_transform'].unique())

g = sns.FacetGrid(data,col='F_transform',
                  col_order=ordered_data,
                  col_wrap=2,
                  aspect=1,
                  height=5.5,
                  legend_out=False,# xlim=5,
                  sharex=False)

g.map(sns.boxplot,'event_number','event_mae_normalized',"F_beta",
      fliersize=0.0,
      width=0.8,
      linewidth=1,
      saturation=0.75,
      palette='muted')

#g.despine(left=True)

#for ax in g.axes.flatten():
#    ax.tick_params(labelbottom=True)

plt.legend(loc='lower right')
plt.tight_layout()
plt.savefig("Earliness.png")
plt.show()
```

```python
import seaborn as sns, matplotlib.pyplot as plt
#sns.set(style="whitegrid")

data = results.loc[results.event_number< 6]
ordered_data = sorted(data['F_dataset'].unique())

g = sns.FacetGrid(data,col='F_dataset',
                  col_order=ordered_data,
                  col_wrap=2,
                  aspect=1,
                  height=5.5,
                  legend_out=False,# xlim=5,
                  sharex=False)

g.map(sns.boxplot,'event_number','event_mae_normalized',"F_lossfunction",
      fliersize=0.0,
      width=0.8,
      linewidth=1,
      saturation=0.75,
      palette='muted')

#g.despine(left=True)

#for ax in g.axes.flatten():
#    ax.tick_params(labelbottom=True)

plt.legend(loc='lower right')
plt.tight_layout()
plt.savefig("Earliness2.png")
plt.show()
```

# Generate a table: Event 1 only

```python
# Drop irrelevant loss functions
table = results_sub
#table = table.loc[table.F_lossfunction!="MSE"]
table = table.loc[table.event_number==1]
table
```

      event_number
      event_mae_normalized
      event_mae
      F_transform
      F_gamma
      F_beta
      F_alpha
      F_dataset
      F_max_epochs
      F_experiment
      Notes
      DOE
      Duration_sec
      MAE
      RUN
      Done

      84
      1
      0.858582
      12.602367
      1.0
      0.75
      0.20
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      34.761585
      13.494128
      4
      1

      140
      1
      0.845391
      12.408745
      1.0
      0.50
      0.20
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      21.894994
      13.414497
      6
      1

      196
      1
      0.880808
      12.928605
      1.0
      0.25
      0.20
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      22.348303
      13.534812
      8
      1

      252
      1
      0.962158
      14.122665
      1.0
      1.00
      0.25
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      16.646838
      14.330710
      10
      1

      308
      1
      0.837693
      12.295752
      1.0
      0.75
      0.25
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      14.832275
      13.319688
      12
      1

      364
      1
      0.969151
      14.225311
      1.0
      0.50
      0.25
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      13.490425
      14.228258
      14
      1

      420
      1
      0.858337
      12.598760
      1.0
      0.25
      0.25
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      18.657403
      13.512953
      16
      1

      476
      1
      0.857773
      12.590487
      1.0
      1.00
      0.30
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      24.645917
      13.639674
      18
      1

      532
      1
      0.852666
      12.515531
      1.0
      0.75
      0.30
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      17.396790
      14.009788
      20
      1

      588
      1
      0.852646
      12.515238
      1.0
      0.50
      0.30
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      22.639477
      13.469660
      22
      1

      644
      1
      0.861820
      12.649891
      1.0
      0.25
      0.30
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      18.598634
      13.493339
      24
      1

      700
      1
      0.838150
      12.302456
      1.0
      1.00
      0.35
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      15.820144
      14.074968
      26
      1

      756
      1
      0.903929
      13.267966
      1.0
      0.75
      0.35
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      13.971335
      14.995211
      28
      1

      812
      1
      0.842175
      12.361537
      1.0
      0.50
      0.35
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      21.252439
      13.375710
      30
      1

      868
      1
      0.856871
      12.577250
      1.0
      0.25
      0.35
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      23.147880
      13.514678
      32
      1

      924
      1
      0.846205
      12.420685
      1.0
      1.00
      0.00
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      19.864759
      13.476562
      34
      1

      980
      1
      0.890684
      13.073553
      1.0
      0.75
      0.00
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      17.115807
      13.846320
      36
      1

      1036
      1
      0.844489
      12.395498
      1.0
      0.50
      0.00
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      25.012746
      13.422136
      38
      1

      1092
      1
      0.851532
      12.498884
      1.0
      0.25
      0.00
      1.0
      0.0
      200.0
      1.0
      NaN
      Full_factorial
      27.431771
      13.426259
      40
      1

```python
import numpy as np
import scipy.stats

def mean_confidence_interval(data, confidence=0.95):
    a = 1.0 * np.array(data)
    n = len(a)
    m, se = np.mean(a), scipy.stats.sem(a)
    h = se * scipy.stats.t.ppf((1 + confidence) / 2., n-1)

    ci = np.round(h,3)
    mean = np.round(m,3)
    string = str(mean)+ " ! " +str(ci)
    return string

df = pd.pivot_table(table, index='F_beta', values="event_mae",
    columns="F_gamma", aggfunc=mean_confidence_interval)

latex = str((df.to_latex(index=True)))
latex = latex.replace('!', '\pm')
print(latex)
```

    \begin{tabular}{lllll}
    \toprule
    F\_gamma &          0.25 &          0.50 &          0.75 &          1.00 \\
    F\_beta &               &               &               &               \\
    \midrule
    0.00   &  12.499 \pm nan &  12.395 \pm nan &  13.074 \pm nan &  12.421 \pm nan \\
    0.20   &  12.929 \pm nan &  12.409 \pm nan &  12.602 \pm nan &           NaN \\
    0.25   &  12.599 \pm nan &  14.225 \pm nan &  12.296 \pm nan &  14.123 \pm nan \\
    0.30   &   12.65 \pm nan &  12.515 \pm nan &  12.516 \pm nan &   12.59 \pm nan \\
    0.35   &  12.577 \pm nan &  12.362 \pm nan &  13.268 \pm nan &  12.302 \pm nan \\
    \bottomrule
    \end{tabular}

    C:\Users\Mike\anaconda3\envs\TF2_CUD11_CRM_PAPER\lib\site-packages\numpy\core\_methods.py:233: RuntimeWarning: Degrees of freedom <= 0 for slice
      ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
    C:\Users\Mike\anaconda3\envs\TF2_CUD11_CRM_PAPER\lib\site-packages\numpy\core\_methods.py:226: RuntimeWarning: invalid value encountered in double_scalars
      ret = ret.dtype.type(ret / rcount)

```python
df = pd.pivot_table(table, index='F_gamma', values="event_mae",
    columns="F_beta", aggfunc=mean_confidence_interval)

df
```

    C:\Users\Mike\anaconda3\envs\TF2_CUD11_CRM_PAPER\lib\site-packages\numpy\core\_methods.py:233: RuntimeWarning: Degrees of freedom <= 0 for slice
      ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
    C:\Users\Mike\anaconda3\envs\TF2_CUD11_CRM_PAPER\lib\site-packages\numpy\core\_methods.py:226: RuntimeWarning: invalid value encountered in double_scalars
      ret = ret.dtype.type(ret / rcount)

      F_beta
      0.00
      0.20
      0.25
      0.30
      0.35

      F_gamma

      0.25
      12.499 ! nan
      12.929 ! nan
      12.599 ! nan
      12.65 ! nan
      12.577 ! nan

      0.50
      12.395 ! nan
      12.409 ! nan
      14.225 ! nan
      12.515 ! nan
      12.362 ! nan

      0.75
      13.074 ! nan
      12.602 ! nan
      12.296 ! nan
      12.516 ! nan
      13.268 ! nan

      1.00
      12.421 ! nan
      NaN
      14.123 ! nan
      12.59 ! nan
      12.302 ! nan

# F tests - all datasets

```python
table
```

      event_number
      event_mae_normalized
      event_mae
      F_lossfunction
      F_loss_weight
      F_dataset
      F_num_blocks
      F_learningrate
      F_batch_size
      F_num_neurons
      F_earlystop_steps
      F_max_epochs
      F_experiment
      Notes
      DOE
      Duration_sec
      MAE
      RUN
      Done
      Name_fix

      0
      1
      1.001540
      115.931302
      MAE
      0.25
      hospital_billing
      1.0
      0.10
      2048.0
      100.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      188.900873
      72.493195
      1
      1
      1

      0
      1
      1.001118
      115.882476
      MAE_td
      0.25
      hospital_billing
      1.0
      0.10
      2048.0
      100.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      265.634506
      72.443599
      2
      1
      1

      0
      1
      1.001128
      115.883626
      MAE
      0.50
      hospital_billing
      1.0
      0.10
      2048.0
      100.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      188.968374
      72.444767
      3
      1
      1

      0
      1
      1.001194
      115.891244
      MAE_td
      0.50
      hospital_billing
      1.0
      0.10
      2048.0
      100.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      269.171463
      72.452505
      4
      1
      1

      0
      1
      1.001493
      115.925927
      MAE
      0.75
      hospital_billing
      1.0
      0.10
      2048.0
      100.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      191.823343
      72.487737
      5
      1
      1

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      0
      1
      1.010220
      40.603386
      MAE_td
      0.75
      helpdesk
      2.0
      0.05
      2048.0
      200.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      147.433831
      31.681558
      156
      1
      1

      0
      1
      1.010238
      40.604102
      MAE
      1.00
      helpdesk
      2.0
      0.05
      2048.0
      200.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      145.472195
      31.682273
      157
      1
      1

      0
      1
      1.010221
      40.603402
      MAE_td
      1.00
      helpdesk
      2.0
      0.05
      2048.0
      200.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      147.056692
      31.681574
      158
      1
      1

      0
      1
      1.010468
      40.613361
      MAE
      1.25
      helpdesk
      2.0
      0.05
      2048.0
      200.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      150.079650
      31.691534
      159
      1
      1

      0
      1
      1.010187
      40.602044
      MAE_td
      1.25
      helpdesk
      2.0
      0.05
      2048.0
      200.0
      5.0
      25.0
      1.0
      NaN
      Full_factorial
      145.060077
      31.680217
      160
      1
      1

160 rows × 20 columns

```python
import statsmodels.api as sm
from statsmodels.formula.api import ols
```

```python
acc_lm = ols('MAE ~ C(F_lossfunction) + C(F_dataset) + C(F_lossfunction) * C(F_dataset)', data=table).fit()
```

```python
anovatable = sm.stats.anova_lm(acc_lm, typ=2) # Type 2 ANOVA DataFrame
```

```python
print(anovatable)
```

                                          sum_sq     df             F    PR(>F)
    C(F_lossfunction)                   0.003422    1.0  1.022939e+00  0.313389
    C(F_dataset)                    66430.692153    1.0  1.985607e+07  0.000000
    C(F_lossfunction):C(F_dataset)      0.002726    1.0  8.146686e-01  0.368135
    Residual                            0.521915  156.0           NaN       NaN

# T-test comparisons with MAE as baseline
## Event_number == 1*

```python
import statsmodels

datasets = ["Sepsis","helpdesk","hospital_billing","traffic_fines"]

losses = ["MAE","MAE_td"]#,"MAE_Mtd","MAE_Etd","MSE"]

# Subset results on first N events
table = results.loc[results.event_number==1]

for loss in losses:
    print("\n\nLOSS: "+loss+"\n\n")
    for dataset in datasets:

        testdata = results.loc[results.F_dataset==dataset]

        baseline = "MAE"

        d1 = testdata.loc[testdata.F_lossfunction==baseline].MAE.values

        comparison = loss

        d2 = testdata.loc[testdata.F_lossfunction==comparison].MAE.values
        out = statsmodels.stats.weightstats.CompareMeans.from_data(d1, d2).summary(use_t=True, alpha=0.05, usevar='pooled')
        print("DATA: "+dataset)
        print("MAE:     "+ str(np.mean(d1)))
        print(comparison+":  "+ str(np.mean(d2)))
        print(out)
```

    LOSS: MAE

    DATA: Sepsis
    MAE:     14.03114797274301
    MAE:  14.03114797274301
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1           0      0.103          0      1.000      -0.203       0.203
    ==============================================================================
    DATA: helpdesk
    MAE:     13.992142083792192
    MAE:  13.992142083792192
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1           0      0.420          0      1.000      -0.826       0.826
    ==============================================================================
    DATA: hospital_billing
    MAE:     55.52804211126678
    MAE:  55.52804211126678
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1           0      0.388          0      1.000      -0.764       0.764
    ==============================================================================
    DATA: traffic_fines
    MAE:     76.8739544625139
    MAE:  76.8739544625139
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1           0      0.067          0      1.000      -0.132       0.132
    ==============================================================================

    LOSS: MAE_td

    DATA: Sepsis
    MAE:     14.03114797274301
    MAE_td:  33.219569865902706
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1    -19.1884      3.447     -5.567      0.000     -25.952     -12.425
    ==============================================================================
    DATA: helpdesk
    MAE:     13.992142083792192
    MAE_td:  586.3274581958929
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1   -572.3353    151.530     -3.777      0.000    -870.023    -274.647
    ==============================================================================
    DATA: hospital_billing
    MAE:     55.52804211126678
    MAE_td:  55.166474504441986
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1      0.3616      0.385      0.940      0.348      -0.395       1.119
    ==============================================================================
    DATA: traffic_fines
    MAE:     76.8739544625139
    MAE_td:  76.82713585844172
                              Test for equality of means
    ==============================================================================
                     coef    std err          t      P>|t|      [0.025      0.975]
    ------------------------------------------------------------------------------
    subset #1      0.0468      0.066      0.708      0.479      -0.083       0.177
    ==============================================================================

```python

max_events = np.max(inference_test.event_number)

if max_events < 10:
    events = 5
else:
    events = 10

inf_results = inference_test.loc[inference_test.event_number < events+1]
inf_results.AE = inf_results.AE /(24.0*3600)

pivottable = pd.pivot_table(inf_results,
                       values='AE',
                    columns=['event_number'], aggfunc=np.mean)

newcols = []
for colno in range(0,len(pivottable.columns)):
    colno = colno + 1
    name = "AE_"+str(colno)+""
    newcols.append(name)

pivottable.columns = newcols
pivottable.index = [0]
pivottable
```

    C:\Users\Mike\anaconda3\envs\TF2_CUD11_CRM_PAPER\lib\site-packages\pandas\core\generic.py:5170: SettingWithCopyWarning:
    A value is trying to be set on a copy of a slice from a DataFrame.
    Try using .loc[row_indexer,col_indexer] = value instead

    See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
      self[name] = value

      AE_1
      AE_2
      AE_3
      AE_4
      AE_5
      AE_6
      AE_7
      AE_8
      AE_9
      AE_10

      0
      12.238627
      12.237781
      12.562031
      12.562555
      13.222226
      13.633513
      13.625139
      14.455449
      14.018538
      14.725038

```python
events
```

    10

```python

```


# 问题设定

在小车倒立杆（CartPole）游戏中，我们希望通过强化学习训练一个智能体（agent），尽可能不断地左右移动小车，使得小车上的杆不倒，我们首先定义CartPole游戏：

CartPole游戏即是强化学习模型的enviorment，它与agent交互，实时更新state，内部定义了reward function，其中state有以下定义：

$$
state \in \mathbb{R}^4
$$

state每一个维度分别代表了：

- 小车位置，它的取值范围是-2.4到2.4
- 小车速度，它的取值范围是负无穷到正无穷
- 杆的角度，它的取值范围是-41.8°到41.8°
- 杆的角速，它的取值范围是负无穷到正无穷

action是一个2维向量，每一个维度分别代表向左和向右移动。

$$
action \in \mathbb{R}^2
$$

小车每一次向左或向右移动都会加1分，这即是reward function，但是如果杆角度大于±12°、小车位置大于±2.4、行动次数大于200次，游戏将会结束。我们希望在游戏结束时得分尽可能大。

# 策略梯度

设计一个网络，其输入是state，输出是对应各个action的概率，并策略梯度（PolicyGradient）进行迭代训练。

我们首先定义$\tau$为一次回合的迹：

$$
\tau = \{s_1, a_1, r_1, \cdots, s_T, a_T, r_T \} \\
$$

$R(\tau)$是这次迹的奖励值之和：

$$
R(\tau) = \sum^{T}_{t=1} r_t
$$

直观地，我们希望最大化：

$$
\bar{R}_{\theta} = \sum_{\tau} R(\tau) P(\tau \lvert \theta) \approx \frac{1}{N} \sum^{N}_{n=1} R(\tau^{n})
$$

则首先对$\bar{R}_{\theta}$求梯度：

$$
\begin{align}
\nabla \bar{R}_{\theta} &= \sum_{\tau} R(\tau) \nabla P(\tau \lvert \theta)  \\
&= \sum_{\tau} R(\tau) P(\tau \lvert \theta) \cdot \frac{\nabla P(\tau \lvert \theta)}{P(\tau \lvert \theta)} \\
&= \sum_{\tau} R(\tau) P(\tau \lvert \theta) \cdot \nabla \log P(\tau \lvert \theta) \\
&\approx \frac{1}{N} \sum^{N}_{n=1} R(\tau^n) \cdot \nabla \log P(\tau^n \lvert \theta)
\end{align}
$$

而对于$P(\tau^n \lvert \theta)$，则可以展开成以下形式：

$$
\begin{align}
p(\tau^n \lvert \theta) &= p(s_1)p(a_1 \lvert s_1, \theta)p(r_1, s_2 \lvert s_1, a_1)p(a_2 \lvert s_2, \theta) \cdots p(a_t \lvert s_t, \theta)p(r_t, s_{t+1} \lvert s_t, a_t) \\
&= p(s_1) \prod_{t} p(a_t \lvert s_t, \theta)p(r_t, s_{t+1} \lvert s_t, a_t)
\end{align}
$$

将上式带入$\log P(\tau^n \lvert \theta)$中：

$$
\begin{align}
\nabla \log P(\tau^n \lvert \theta) &= \nabla \log \left (p(s_1) \prod_{t} p(a_t \lvert s_t, \theta)p(r_t, s_{t+1} \lvert s_t, a_t) \right) \\
&= \nabla \log p(s_1) + \sum^{T}_{t=1} \nabla \log p(a_t \lvert s_t, \theta) + \sum^{T}_{t=1}  \nabla p(r_t, s_{t+1} \lvert s_t, a_t) \\
&= \sum^{T}_{t=1} \nabla  \log p(a_t \lvert s_t, \theta)
\end{align}
$$

最终$\nabla \bar{R}_{\theta}$将改写为：

$$
\begin{align}
\nabla \bar{R}_{\theta} &\approx \frac{1}{N} \sum^{1}_{N} R(\tau^n) \cdot \nabla \log P(\tau^n \lvert \theta) \\
&= \frac{1}{N} \sum^{N}_{n=1} R(\tau^n) \sum^{T_n}_{t=1} \nabla  \log p(a_t \lvert s_t, \theta) \\
&= \frac{1}{N} \sum^{N}_{n=1} \sum^{T_n}_{t=1} R(\tau^n) \nabla  \log p(a_t \lvert s_t, \theta)
\end{align}
$$

本质上是最小化N回合采样出的action与网络输出的action的交叉熵的基础上乘以$R(\tau^n)$：

$$
- \sum^{N}_{n=1} R(\tau^n) \cdot a_i \log p_i
$$

需要注意的是，$R(\tau^n)$对于不同的问题计算方式是不同的，在CartPole中，我们更关注回合开始时的奖励，因为他们直接影响了我们是否有机会进行更可能多的动作，所以在这个问题中，$R(\tau^n)$是这样计算的：

```
# Copy r_buffer
r_buffer = self.r_buffer
# Init r_tau
r_tau = 0
# Calculate r_tau
for index in reversed(range(0, len(r_buffer))):
    r_tau = r_tau * self.gamma + r_buffer[index]
```

# 代码实现

首先导入必要包：

```python
import tensorflow as tf
import numpy as np
import gym
import sys

sys.path.append('.')
```

实现Agent类：

```python
class Agent(object):

    def __init__(self, a_space, s_space, **options):

        self.session = tf.Session()

        self.a_space, self.s_space = a_space, s_space

        self.s_buffer, self.a_buffer, self.r_buffer = [], [], []

        self._init_options(options)
        self._init_input()
        self._init_nn()
        self._init_op()

    def _init_input(self):
        self.s = tf.placeholder(tf.float32, [None, self.s_space])
        self.r = tf.placeholder(tf.float32, [None, ])
        self.a = tf.placeholder(tf.int32, [None, ])

    def _init_nn(self):
        # Kernel init.
        w_init = tf.random_normal_initializer(.0, .3)
        # Dense 1.
        dense_1 = tf.layers.dense(self.s,
                                  32,
                                  tf.nn.relu,
                                  kernel_initializer=w_init)
        # Dense 2.
        dense_2 = tf.layers.dense(dense_1,
                                  32,
                                  tf.nn.relu,
                                  kernel_initializer=w_init)
        # Action logits.
        self.a_logits = tf.layers.dense(dense_2,
                                        self.a_space,
                                        kernel_initializer=w_init)
        # Action prob.
        self.a_prob = tf.nn.softmax(self.a_logits)

    def _init_op(self):
        # One hot action.
        action_one_hot = tf.one_hot(self.a, self.a_space)
        # Calculate cross entropy.
        cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=action_one_hot, logits=self.a_logits)
        self.loss_func = tf.reduce_mean(cross_entropy * self.r)
        self.train_op = tf.train.AdamOptimizer(self.learning_rate).minimize(self.loss_func)
        self.session.run(tf.global_variables_initializer())

    def _init_options(self, options):

        try:
            self.learning_rate = options['learning_rate']
        except KeyError:
            self.learning_rate = 0.001

        try:
            self.gamma = options['gamma']
        except KeyError:
            self.gamma = 0.95

    def predict(self, state):
        action_prob = self.session.run(self.a_prob, feed_dict={self.s: state[np.newaxis, :]})
        return np.random.choice(range(action_prob.shape[1]), p=action_prob.ravel())

    def save_transition(self, state, action, reward):
        self.s_buffer.append(state)
        self.a_buffer.append(action)
        self.r_buffer.append(reward)

    def train(self):
        # Copy r_buffer
        r_buffer = self.r_buffer
        # Init r_tau
        r_tau = 0
        # Calculate r_tau
        for index in reversed(range(0, len(r_buffer))):
            r_tau = r_tau * self.gamma + r_buffer[index]
            self.r_buffer[index] = r_tau
        # Minimize loss.
        _, loss = self.session.run([self.train_op, self.loss_func], feed_dict={
            self.s: self.s_buffer,
            self.a: self.a_buffer,
            self.r: self.r_buffer,
        })

        self.s_buffer, self.a_buffer, self.r_buffer = [], [], []
```

# 实验结果

通过`gym`初始化`CartPole`游戏环境并执行训练：

```python
import matplotlib.pyplot as plt

%matplotlib inline

env = gym.make('CartPole-v0')
env.seed(1)
env = env.unwrapped

model = Agent(env.action_space.n, env.observation_space.shape[0])

r_sum_list, r_episode_sum = [], None

for episode in range(500):
    # Reset env.
    s, r_episode = env.reset(), 0
    # Start episode.
    while True:
        # if episode > 80:
        #     env.render()
        # Predict action.
        a = model.predict(s)
        # Iteration.
        s_n, r, done, _ = env.step(a)
        if done:
            r = -5
        r_episode += r
        # Save transition.
        model.save_transition(s, a, r)
        s = s_n
        if done:
            if r_episode_sum is None:
                r_episode_sum = sum(model.r_buffer)
            else:
                r_episode_sum = r_episode_sum * 0.99 + sum(model.r_buffer) * 0.01
            r_sum_list.append(r_episode_sum)
            break
    # Start train.
    model.train()
    if episode % 50 == 0:
        print("Episode: {} | Reward is: {}".format(episode, r_episode))
```

    WARN: gym.spaces.Box autodetected dtype as <class 'numpy.float32'>. Please provide explicit dtype.
    Episode: 0 | Reward is: 17.0
    Episode: 50 | Reward is: 71.0
    Episode: 100 | Reward is: 26.0
    Episode: 150 | Reward is: 50.0
    Episode: 200 | Reward is: 102.0
    Episode: 250 | Reward is: 194.0
    Episode: 300 | Reward is: 197.0
    Episode: 350 | Reward is: 71.0
    Episode: 400 | Reward is: 147.0
    Episode: 450 | Reward is: 182.0

最后绘制出回合与奖励函数的曲线：

```python
plt.plot(np.arange(len(r_sum_list)), r_sum_list)
plt.title('Actor Only on CartPole')
plt.xlabel('Episode')
plt.ylabel('Total Reward')
plt.show()
```