原文:
towardsdatascience.com/importance-sampling-with-python-93b03eb9ca22
图片由 Edge2Edge Media 提供,来源于 Unsplash
·发表于 Towards Data Science ·阅读时间 5 分钟·2023 年 5 月 10 日
--
在数据科学家必须知道的各种采样方法中,最重要的方法之一就是所谓的“重要性采样”。
这种方法使我们能够即使我们实际上只能从另一个分布中采样,也能从一个分布中采样! 让我们看看它是如何工作的。
假设,例如,从分布 g(x) 中采样是不可行的,因为,例如,这样做成本太高。但与此同时,我们有一个可以采样的分布 f(x),我们称之为重要性分布。
我们可以通过对分布 f(x) 进行采样来计算我们真正感兴趣的分布 g(x) 的统计信息。让我们看看如何做。
想象一下,我们有一个表示每个骰子面的概率的分布 f(x)。如果骰子是“公平的”,每一面都有 1/6 的概率,因此我们可以将分布表示如下。
公平分配(图片由作者提供)
我们还有另一个分布 g(x),我们希望从中采样,但由于某种原因被阻止。在这种情况下,骰子是不公平的,因此分布是有偏的。所以有些面会比其他面有更高的概率。
偏倚分布(图片由作者提供)
使用我们的数学概念,我们能够计算每个分布的期望值。因此,例如,第一种分布 f(x) 的 E[x] 将是:
期望值 f(x)(图片由作者提供)
同样的原理自然适用于 g(x)。
预期值 g(x)(作者提供的图片)
现在想象我们想通过抽样从我们的总体中计算统计量。例如,我们想计算掷 n 次骰子的结果的平均值。
我们掷一个公平骰子 n 次,我们知道根据中心极限定理,随着 n 的增加,这个平均值将趋向于预期值。
作者提供的图片
现在我们想通过掷 n 次另一个骰子,即不公平的骰子,来计算相同的统计量,那个骰子具有不同的概率分布。问题是这个骰子不存在,因此我们无法实验!
那我们该如何做到这一点呢?我们可以通过始终使用公平骰子来计算这个统计量,但使用一个“技巧”。
我们知道如何计算这个骰子的预期值,使用分布 g(x)。接下来我们要做的是乘以并除以相同的数量 f(x)。
作者提供的图片
现在如果我们将 x 叫做求和中的第一部分,这个值实际上是 f(x) 的预期值,其中 x 是加权的。
作者提供的图片
所以我们可以使用之前的相同思路,进行一个抽样,其中 我们按 g(x)/f(x) 权重每次抽取,结果应该接近 g 的预期值。
一切都很好,但这真的有效吗?让我们做一些实验!
首先,我们导入一些需要的库。
import numpy as np
import matplotlib.pyplot as plt
现在我们用两个 numpy 数组表示两个骰子的分布。第一个是公平骰子,每一面的概率相同。第二个则是每一面概率不同的骰子。
f = np.array([1/6, 1/6, 1/6, 1/6, 1/6, 1/6])
g = np.array([0.4, 0.3 ,0.1 ,0.1, 0.06, 0.04])
如果你愿意,可以使用 Matplotlib 绘制分布图。
plt.bar(np.arange(1,7), f)
plt.show()
作者提供的图片
plt.bar(np.arange(1,7), g)
plt.show()
作者提供的图片
现在让我们定义一个函数来计算实验的经验均值。也就是说,我们掷一个骰子 n 次,然后将获得的结果总和除以 n。选择的数字 n 越大,经验均值就会越接近预期值。
def compute_avg(distr, n = 10_000):
mean = 0
for i in range(n):
mean += np.random.choice(a = np.arange(1,7), p=distr)
print(f"average from sampling: {mean/n}")
如果你现在在两个分布 f 和 g 上计算这个经验均值,你应该会找到一个类似于预期值的均值。
compute_avg(f)
compute_avg(g)
问题在于我们必须假设一个你无法直接计算 g 的经验均值的情况,因为例如,你没有这样的骰子,因此无法实验。你唯一拥有的骰子是公平骰子,尽管如此,你知道两个骰子的分布。
然后,正如我们之前看到的,我们可以创建一个从分布 f 中抽样的函数,然后通过之前展示的方式加权提取的数字,我们可以计算出好像它是从分布 g 中提取的均值。现在我们要做的就是编写这个函数,看看它是否真的有效。
def importance_sampling(f, g, n = 10_000):
mean = 0
for i in range(n):
x = np.random.choice(a = np.arange(1,7), p=f)
weight = g[x-1]/f[x-1]
x = x*weight
mean += x
print(f"average from sampling: {mean/n}")
因此,我们在之前提到的 f 和 g 分布上进行了 n = 10,000 次的重要性采样。
importance_sampling(f,g)
这个函数的结果是 2.24920,非常接近预期值!所以我们通过编写 Python 代码具体展示了这个方法的有效性!
在这篇文章中,我们探讨了数据科学家最重要的采样技术之一。重要性采样允许我们从一个分布中进行采样,即使我们只能访问另一个分布。如果例如从目标分布中采样成本过高,或者由于任何原因不可能进行采样,也可能发生这种情况。我希望你在这篇文章中学到了有用的东西,如果你对这类文章感兴趣,可以在 Medium 上关注我!😉
马尔切洛·波利提