从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
上图显示我的算法中的某些内容不正确,因为此椭圆的长轴不在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)
我在使用rvs
或协方差矩阵定义时是否犯了一个简单的错误?如果算法以其他方式存在缺陷,是否有更简单的方法从椭圆的长轴/短轴开始定义这样的选择函数?
答案 0 :(得分:4)
协方差矩阵在这里是不正确的,你不能从结果行为中做出推论。 rvs
方法在这种情况下给出不同结果的事实仅仅反映了rvs
和pdf
函数以不同方式预处理它们的参数这一事实。而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 = 4
和a - 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
可提供以下内容: