def leave_one_out(x, y, is_continuous):
    """
    使用留一法验证法对模型进行评估
    :return: 模型留一法验证下的正确率
    """
    cnt = 0
    for i in range(len(x)):
        train_x = np.delete(x, i, 0)
        train_y = np.delete(y, i, 0)
        test_x = x[i]
        test_y = y[i]
        naive_bayes = NaiveBayes(train_x, train_y, is_continuous)
        naive_bayes.train()
        test_result = naive_bayes.inference(test_x)
        if test_result == test_y:
            cnt += 1
    return cnt / len(x)
        [1, 1, 0, 0, 1, 0, 0.437, 0.211],
        [1, 1, 1, 1, 1, 0, 0.666, 0.091],
        [0, 2, 2, 0, 2, 1, 0.243, 0.267],
        [2, 2, 2, 2, 2, 0, 0.245, 0.057],
        [2, 0, 0, 2, 2, 1, 0.343, 0.099],
        [0, 1, 0, 1, 0, 0, 0.639, 0.161],
        [2, 1, 1, 1, 0, 0, 0.657, 0.198],
        [1, 1, 0, 0, 1, 1, 0.360, 0.370],
        [2, 0, 0, 2, 2, 0, 0.593, 0.042],
        [0, 0, 1, 1, 1, 0, 0.719, 0.103],
    ], dtype=object)
    y = np.array([1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
    is_continuous = [False, False, False, False, False, False, True, True]
    naive_bayes = NaiveBayes(x, y, is_continuous)
    naive_bayes.train()
    print(naive_bayes.inference([0, 0, 0, 0, 0, 0, 0.697, 0.460]))

"""
y = 0
[0.33333333 0.25       0.41666667]
[0.33333333 0.41666667 0.25      ]
[0.41666667 0.33333333 0.25      ]
[0.25       0.41666667 0.33333333]
[0.25       0.33333333 0.41666667]
[0.63636364 0.36363636]
---
y = 1
[0.36363636 0.45454545 0.18181818]
[0.54545455 0.36363636 0.09090909]
[0.63636364 0.27272727 0.09090909]
[0.72727273 0.18181818 0.09090909]
def main():
    raw_data = pd.read_csv("student_data.csv")
    y = np.array(np.array(raw_data).T[0].T, dtype=int)
    details = [
        (1, 3, 4),
        (2, 1, 3),
        (3, 1, 4),
    ]
    for feat, st, ed in details:
        x = np.array(raw_data.iloc[:, st: ed])
        is_continuous = [True] * feat
        acc = leave_one_out(x, y, is_continuous)
        print(f"accuracy using {feat} feature: {acc * 100}%")

    fig = make_subplots(
        rows=1, cols=2,
        column_width=[0.6, 0.4],
        specs=[
            [{"type": "scatter3d"}, {"type": "scatter"}],
        ],
        subplot_titles=(
            "visualization of training data",
            "ROC curve of models using different features",
        )
    )
    fig.add_trace(
        go.Scatter3d(
            x=np.array(raw_data).T[1],
            y=np.array(raw_data).T[2],
            z=np.array(raw_data).T[3],
            marker=dict(color=y), mode="markers",
            showlegend=False,
        ),
        row=1, col=1
    )
    fig.add_shape(
        type="line", line=dict(dash="dash"),
        x0=0, x1=1, y0=0, y1=1,
        row=1, col=2,
    )
    for i in range(1, 4):
        train_x = np.array(raw_data.iloc[:20, i: i + 1])
        train_y = np.array(np.array(raw_data.iloc[:20, :]).T[0].T, dtype=int)
        inference_x = np.array(raw_data.iloc[20:, i: i + 1])
        inference_y = np.array(np.array(raw_data.iloc[20:, :]).T[0].T, dtype=int)
        is_continuous = [True]
        naive_bayes = NaiveBayes(train_x, train_y, is_continuous)
        naive_bayes.inference = MethodType(inference, naive_bayes)
        naive_bayes.train()
        ans = []
        tot, cnt = [0, 0], [0, 0]
        for x_i, y_i in zip(inference_x, inference_y):
            ans.append([naive_bayes.inference(x_i), y_i])
            tot[y_i] += 1
        ans.sort()
        auc = 0.0
        plot_x, plot_y = [0], [0]
        for elem in ans:
            cnt[elem[1]] += 1
            plot_x.append(cnt[0] / tot[0])
            plot_y.append(cnt[1] / tot[1])
            if plot_x[-1] != plot_x[-2]:
                auc += (plot_x[-1] - plot_x[-2]) * plot_y[-1]
        fig.add_trace(
            go.Scatter(
                x=plot_x, y=plot_y,
                name=f"feature {i} (AUC={round(auc, 4)})",
                mode="lines",
            ),
            row=1, col=2,
        )
    fig.update_xaxes(title_text="False Positive Rate", range=[-0.01, 1.01], row=1, col=2)
    fig.update_yaxes(title_text="True Positive Rate", range=[-0.01, 1.01], row=1, col=2)
    fig["layout"]["scene"]["xaxis"] = {"title": {"text": "height"}}
    fig["layout"]["scene"]["yaxis"] = {"title": {"text": "weight"}}
    fig["layout"]["scene"]["zaxis"] = {"title": {"text": "shoe size"}}
    fig.show()