使用scipy在xy平面中定义蒙特卡罗采样椭圆

时间:2017-06-15 16:42:41

标签: python numpy scipy montecarlo scientific-computing

从x-y平面中的一大组点开始,我想选择这些点的子集,这些点优先采用由已知长轴和短轴的椭圆定义的方式。例如:

import numpy as np 

npts = int(1e5)
lim = 3
x = np.random.uniform(-lim, lim, npts)
y = np.random.uniform(-lim, lim, npts)

major_axis = np.array((1, 1))
minor_axis = np.array((-0.25, 0.25))

上述两个矢量定义了一个椭圆,其轴比为4-1,长轴指向y = x线。因此,我试图写下一个蒙特卡罗采样算法,如果x - y平面上的一个点位于输入主轴上(在这种情况下是线y = x),则它具有增强的选择概率。位于短轴上的点(在这种情况下,线y = -x),其中概率增强因子简单地由主 - 轴比率确定(在这种情况下因此为4)。

我一直在尝试使用pdf的{​​{1}}方法执行此操作,但我认为我必须使用该方法不正确。我的方法是通过将主轴和短轴视为本征点来定义协方差矩阵,在每个点上使用scipy.stats.multivariate_normal方法,对这些概率进行排序,然后选择顶部{{1这些概率。

pdf

incorrect distribution

上图显示我的算法中的某些内容不正确,因为此椭圆的长轴不在y = x行上。我怀疑协方差矩阵没有正确定义,但当我使用Nselect方法使用相同的协方差矩阵时,我得到了预期的分布:

from scipy.stats import multivariate_normal
cov = np.array((major_axis, minor_axis))
p = np.vstack((x, y)).T
prob_select = multivariate_normal.pdf(p, cov=cov)
idx_select = np.argsort(prob_select)
Nselect = len(x)/10
result_x = x[idx_select][-Nselect:]
result_y = y[idx_select][-Nselect:]

fig, ax = plt.subplots(1, 1)
__=ax.scatter(result_x, result_y, s=1)
xlim = ax.set_xlim(-3, 3)
ylim = ax.set_ylim(-3, 3)

expected distribution from <code>rvs</code>

我在使用rvs或协方差矩阵定义时是否犯了一个简单的错误?如果算法以其他方式存在缺陷,是否有更简单的方法从椭圆的长轴/短轴开始定义这样的选择函数?

1 个答案:

答案 0 :(得分:4)

为什么结果不一致

协方差矩阵在这里是不正确的,你不能从结果行为中做出推论。 rvs方法在这种情况下给出不同结果的事实仅仅反映了rvspdf函数以不同方式预处理它们的参数这一事实。而rvs基本上将其参数直接传递给numpy.multivariate_normal ...

# https://github.com/scipy/scipy/blob/v0.14.0/scipy/stats/_multivariate.py#L405
dim, mean, cov = _process_parameters(None, mean, cov)
out = np.random.multivariate_normal(mean, cov, size)
return _squeeze_output(out)

pdf将协方差矩阵传递给计算伪逆的函数:

# https://github.com/scipy/scipy/blob/v0.14.0/scipy/stats/_multivariate.py#L378
dim, mean, cov = _process_parameters(None, mean, cov)
x = _process_quantiles(x, dim)
prec_U, log_det_cov = _psd_pinv_decomposed_log_pdet(cov)
out = np.exp(self._logpdf(x, mean, prec_U, log_det_cov))
return _squeeze_output(out)

如果协方差矩阵形成良好,这些只能保证给出一致的结果。

构建格式良好的矩阵

协方差矩阵只是每个相应维度配对的协方差,因此它的定义是对称的。

文档重申了这一点:

  

cov :2-D array_like,形状(N,N)

     

分布的协方差矩阵。对于正确的采样,它必须是对称的和正半定的。

鉴于您希望从主轴和次轴获得协方差矩阵,您真正想要的是解决反向特征向量问题!好极了!我希望我们有mathjax ......

我们需要一个对称矩阵C = [[a, b], [b, a]],使[1, 1][1, -1]是特征向量,我们还希望特征值的比率为四比一。这意味着C * [1, 1] = [4, 4]C * [1, -1] = [1, -1]。选择1作为我们的次要指数特征值,将4作为我们的主要指数特征值,并使用变量手动进行矩阵乘法,得到a + b = 4a - b = 1。所以A是2.5,b是1.5,C是[[2.5, 1.5], [1.5, 2.5]]

我们也可以使用矩阵方程来找到更直接的解。如果E是特征向量矩阵[[1, 1], [1, -1]]lambda是特征值[[4, 0], [0, 1]]的对角矩阵,那么我们正在寻找矩阵X,以便: / p>

X @ E = E @ lambda

其中@表示矩阵乘法(如Python 3.5 +)。

这意味着

X = E @ lambda @ E ^ -1

numpy那是

>>> E = numpy.array([[1, 1], [1, -1]])
>>> lambda_ = numpy.array([[4, 0], [0, 1]])
>>> E @ lambda_ @ numpy.linalg.pinv(E)
array([[ 2.5,  1.5],
       [ 1.5,  2.5]])

在代码中将其用作cov可提供以下内容:

Chart of a correctly skewed ellipse.