使用 PyMC 进行简单的欺诈检测


使用PyMC 和贝叶斯统计作为机器学习的替代方案。

在我最近的一个项目中,我们面临着数据非常有限的预测问题。每组数据都需要花费专家数小时来编制,结果并不总是成功的。因此,我们正在寻找一种工具来满足这些要求,因为人工智能无法通过有限数量的原始数据进行训练。因此,我们转向统计方法,即使用 Python 包 PyMC 的贝叶斯统计。我将解释它所基于的理论,并以骰子欺诈检测为例进行描述。

贝叶斯统计学
贝叶斯统计学是统计学的一个分支,它利用贝叶斯定理来更新我们对一个假设的概率的信念,因为有了新的数据。贝叶斯定理指出,在某些数据(D)的情况下,一个假设(H)的概率等于在假设(D|H)的情况下数据的概率乘以假设的先验概率(p(H))除以数据的总概率(p(D))。这使我们能够在新数据出现时更新我们对某一假设的信念,而不是仅仅依赖手头的数据。

实现贝叶斯统计的最流行的Python包之一是PyMC。PyMC是一个强大的软件包,允许用户轻松定义、拟合和分析贝叶斯模型。它包括各种内置分布,如正态分布、二项分布和泊松分布,以及各种采样器,如Metropolis-Hastings和No-U-Turn Sampler(NUTS)。PyMC还包括各种方便的工具,用于诊断和可视化你的模型的结果。

在使用PyMC时需要记住的一件事是,你应该从概率分布的角度来考虑问题,而不是从点估计的角度。这可能需要一些时间来适应,但这对于准确建立复杂系统的模型是至关重要的。你得到的每个结果都有一个概率。因此,置信区间是PyMC的任何结果的关键部分。与神经网络相比,这是一个优势。

贝叶斯统计学使用先验概率和后验概率这个术语。先验概率是在任何数据被看到之前的概率分布。基本上,它显示了通过简单猜测所有假设参数的可能结果范围。然而,后验概率是考虑到数据的分布,即(D|H)乘以p(H)。

掷出一个被篡改的骰子
作为一个例子,我们正在使用PyMC来模拟掷骰子的过程。我们想找出骰子是被篡改过的还是可以使用的。我们规定每个面(1-6)的概率用Dirichlet分布来建模,好的骰子的概率相同。我们还假设观察到的数据,也就是掷骰子的结果,遵循一个具有参数p的分类分布,也就是每个面的推断概率。没有任何数据,这就是先验概率。然后我们使用马尔科夫链蒙特卡洛(MCMC)抽样对模型进行推断,并使用样本来推断每个面的概率,即后验概率。被篡改的骰子在12次滚动中的7次产生了6--所以这真的很明显。

下面是一个示例代码。

import numpy as np  
import pymc as pm  
from matplotlib import pyplot as plt  
  
# Defining the dice and preparing data  
tampered_dice = [1 / 12, 1 / 12, 1 / 12, 1 / 12, 1 / 12, 7 / 12]  
good_dice = [1 / 6] * 6  
num_rolls = 10000  
x = list(range(0, num_rolls, 1))  
  
for idx, dice in enumerate([tampered_dice, good_dice]):  
    # generate the dice rolls data  
    p = np.array(dice)  
    dice_rolls = np.random.choice(6, size=num_rolls, p=p)  
  
    # specify the dice model  
    with pm.Model() as dice_model:  
        p = pm.Dirichlet("p", a=np.ones(6))  
  
        # specify the likelihood  
        face = pm.Categorical(
"face", p=p, observed=dice_rolls)  
  
        # perform inference using the data  
        trace = pm.sample(draws=100, tune=100, chains=2)  
  
        # sampling data from before and after data is available  
        prior_predictive = pm.sample_prior_predictive()  
        post_pred = pm.sample_posterior_predictive(trace)  
  
    # presenting prior predictions  
    fig, ax = plt.subplots()  
    ax.hist(prior_predictive.observed_data.face)  
    plt.xlabel(
"Die face")  
    plt.ylabel(
"Occurences in 10k rolls.")  
    if idx == 0:  
        plt.title(
"Tampered dice")  
    else:  
        plt.title(
"Good dice")  
    plt.savefig(f
"prior_predictive_{idx}.png", dpi=100)  
    plt.show()  
  
    # presenting posterior predictions  
    trace.extend(post_pred)  
  
    fig, ax = plt.subplots()  
    ax.hist(trace.observed_data.face)  
    plt.xlabel(
"Die face")  
    plt.ylabel(
"Occurences in 10k rolls.")  
    if idx == 0:  
        plt.title(
"Tampered dice")  
    else:  
        plt.title(
"Good dice")  
    plt.savefig(f
"posterior_predictive_{idx}.png", dpi=100)  
    plt.show()  
  
    # calculate the expected probabilities of a fair dice  
    expected_probs = np.ones(6) / 6  
  
    # calculate the difference between the posterior probabilities and the expected probabilities  
    prob_diff = np.abs(trace.posterior.p - expected_probs)  
  
    # calculate the mean and standard deviation of the difference  
    mean_diff = np.mean(prob_diff, axis=0)  
    std_diff = np.std(prob_diff, axis=0)  
  
    # set a threshold for the difference  
    threshold = 0.05  
  
    # check if the difference between the inferred probabilities and the expected probabilities is above the threshold  
    tampered = mean_diff > threshold  
  
    if tampered.any():  
        print(
"Dice may have been tampered with.")  
    else:  
        print(
"Dice does not seem to have been tampered with.")

通过运行它,程序会检查骰子的面是否在理想骰子的5%的允许偏差之内。很可能,你的普通家用骰子会被这段代码视为被篡改了,因为面1比6重,使6平均比1出现得更多。对于先验概率,我选择了100次抽签。抽签是程序为获得潜在的模型参数而进行的wyld猜测的次数。建议使用更大的数值,例如1000,以便在概率分布中具有足够的颗粒度。

为什么选择 PyMC?
现在PyMC的优点和缺点是什么?PyMC 是一个功能强大的包,允许用户轻松定义、拟合和分析模型。它提供了多种适用于各种模型的内置分布和采样器。PyMC 也非常灵活,可以处理复杂的模型。然而,PyMC 是一个概率编程库,需要一些时间来适应。理解概率分布和贝叶斯统计的概念很重要。PyMC 的计算成本可能很高,尤其是对于大型和复杂的模型,并且可能不适合实时应用程序或大型数据集。特别是因为 PyMC 是用 Python 构建的。贝叶斯方法是数据分析的强大工具,PyMC 使得在 Python 中实现这些方法变得容易。然而,PyMC 是
具有不同要求和优势的 PyMC 替代品是:

  • Stan:用 C++ 编写,因此对于大型复杂模型而言比 PyMC 更快。
  • JAGS:用 C++ 编写
  • Edward:建立在 TensorFlow 之上,允许使用深度学习模型。对贝叶斯深度学习问题很有用。

在概率预测中发现了相关应用,概率预测是一种提供一系列可能结果的预测,而不是单点估计。一些例子包括天气预报、金融预测和目前在欧洲最相关的能源预测。

有时,神经网络和深度学习会产生看似神奇的结​​果。目前最突出的例子是ChatGPT和MidJourney,他们只能部分理解成果,而贝叶斯统计要求我们思考观察数据背后的模型,从而更深入地理解手头的问题。虽然不如人工智能强大,但概率方法可以帮助我们为人工智能准备数据和设定要求。对问题的更多理解通常是一个关键的好处。