协方差矩阵的主轴与其角度不对齐
Principle axes of covariance matrix does not line up with its angle
我正在尝试获取协方差的主轴(梯度和截距)。我正在使用排序后的特征向量来计算椭圆的角度,但是当我针对长轴绘制生成的椭圆时,它们没有对齐。
有没有人有什么想法?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
def eigsorted(cov):
vals, vecs = np.linalg.eigh(cov)
order = vals.argsort()[::-1]
return vals[order], vecs[:,order]
def orientation_from_covariance(cov, sigma):
vals, vecs = eigsorted(cov)
theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
w, h = 2 * sigma * np.sqrt(vals)
return w, h, theta
def plot_ellipse(ax, mu, covariance, color, linewidth=2, alpha=0.5):
x, y, angle = orientation_from_covariance(covariance, 2)
e = Ellipse(mu, x, y, angle=angle)
e.set_alpha(alpha)
e.set_linewidth(linewidth)
e.set_edgecolor(color)
e.set_facecolor(color)
e.set_fill(False)
ax.add_artist(e)
return e
from statsmodels.stats.moment_helpers import corr2cov
corr = np.eye(2)
corr[0, 1] = corr[1, 0] = 0.7
cov = corr2cov(corr, [1, 5])
mu = [1, 1]
vectors = eigsorted(cov)[1].T
gradients = [v[0] / v[1] for v in vectors]
intercepts = [mu[1] - (gradient*mu[0]) for gradient in gradients]
plt.scatter(*np.random.multivariate_normal(mu, cov, size=9000).T, s=1);
plot_ellipse(plt.gca(), mu, cov, 'k')
_x = np.linspace(*plt.xlim())
for i,g in zip(intercepts, gradients):
plt.plot(_x, i + (_x * g), 'k');
问题出在下一行
# gradients = [v[0] / v[1] for v in vectors] # wrong
gradients = [v[1] / v[0] for v in vectors] # correct
因为梯度是 y
相对于 x
的变化。然后图形看起来像这样。
我还在绘图开始之前添加了 plt.figure()
,在 plot_ellipse
调用之后添加了 plt.axis("equal")
。
我还想引用 numpy.linalg.eigh 文档:
w : (…, M) ndarray
The eigenvalues in ascending order, each repeated according to its multiplicity.
因此可以省略 eigsorted
函数。
我正在尝试获取协方差的主轴(梯度和截距)。我正在使用排序后的特征向量来计算椭圆的角度,但是当我针对长轴绘制生成的椭圆时,它们没有对齐。
有没有人有什么想法?
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
def eigsorted(cov):
vals, vecs = np.linalg.eigh(cov)
order = vals.argsort()[::-1]
return vals[order], vecs[:,order]
def orientation_from_covariance(cov, sigma):
vals, vecs = eigsorted(cov)
theta = np.degrees(np.arctan2(*vecs[:,0][::-1]))
w, h = 2 * sigma * np.sqrt(vals)
return w, h, theta
def plot_ellipse(ax, mu, covariance, color, linewidth=2, alpha=0.5):
x, y, angle = orientation_from_covariance(covariance, 2)
e = Ellipse(mu, x, y, angle=angle)
e.set_alpha(alpha)
e.set_linewidth(linewidth)
e.set_edgecolor(color)
e.set_facecolor(color)
e.set_fill(False)
ax.add_artist(e)
return e
from statsmodels.stats.moment_helpers import corr2cov
corr = np.eye(2)
corr[0, 1] = corr[1, 0] = 0.7
cov = corr2cov(corr, [1, 5])
mu = [1, 1]
vectors = eigsorted(cov)[1].T
gradients = [v[0] / v[1] for v in vectors]
intercepts = [mu[1] - (gradient*mu[0]) for gradient in gradients]
plt.scatter(*np.random.multivariate_normal(mu, cov, size=9000).T, s=1);
plot_ellipse(plt.gca(), mu, cov, 'k')
_x = np.linspace(*plt.xlim())
for i,g in zip(intercepts, gradients):
plt.plot(_x, i + (_x * g), 'k');
问题出在下一行
# gradients = [v[0] / v[1] for v in vectors] # wrong
gradients = [v[1] / v[0] for v in vectors] # correct
因为梯度是 y
相对于 x
的变化。然后图形看起来像这样。
我还在绘图开始之前添加了 plt.figure()
,在 plot_ellipse
调用之后添加了 plt.axis("equal")
。
我还想引用 numpy.linalg.eigh 文档:
w : (…, M) ndarray
The eigenvalues in ascending order, each repeated according to its multiplicity.
因此可以省略 eigsorted
函数。