How to plot a 3D Confidence Ellipsoid for 3D PCA plots in Python?

问题描述 投票:0回答:0

我想在 3D 图中围绕我的 PCA 集群绘制一个 2-STD 置信椭圆体; 我想要实现的是:https://www.originlab.com/fileExchange/details.aspx?fid=280 在 Python 中。我很感激任何意见。

我尝试了一些使用 Pearson 系数和集群协方差矩阵特征值的方法。 但是,椭圆体角度似乎偏离了,我无法使用以下代码重现 PC1 与 PC2 的 2D 置信椭圆:

def confidence_ellipse3D(x, y, z, ax, n_std=2.0, facecolor='none', **kwargs): """ 创建 xy 的协方差置信椭圆图。

Parameters
----------
x, y : array-like, shape (n, )
    Input data.

ax : matplotlib.axes.Axes
    The axes object to draw the ellipse into.

n_std : float
    The number of standard deviations to determine the ellipse's radiuses.

**kwargs
    Forwarded to `~matplotlib.patches.Ellipse`

Returns
-------
matplotlib.patches.Ellipse
"""
if x.size != y.size or x.size != z.size:
    raise ValueError("x and y must be the same size")
cov = np.cov(  np.stack((x, y, z), axis=0)  )
# https://www.ncbi.nlm.nih.gov/pmc/articles/PMC5816993/#:~:text=Go%20to%3A-,PEARSON%20CORRELATION%20COEFFICIENT,%CF%81'%20as%20population%20correlation%20coefficient.
#pearsonxy = cov[0, 1]/np.sqrt(abs(cov[0, 0] * cov[1, 1])) # Formula https://slideplayer.com/10694667/37/images/slide_1.jpg     
# Using a special case to obtain the eigenvalues of this
# two-dimensionl dataset.
# ell_radius_x^2 + ell_radius_y^2 = 2
_,s,rotation = linalg.svd(cov)#https://en.wikipedia.org/wiki/Covariance_matrix
radii = 1.0/np.sqrt(s)
# Calculating the stdandard deviation of x from
# the squareroot of the variance and multiplying
# with the given number of standard deviations.
scale_x = np.sqrt(abs(cov[0, 0])) * n_std
mean_x = np.mean(x)
# calculating the stdandard deviation of y ...
scale_y = np.sqrt(abs(cov[1, 1])) * n_std
mean_y = np.mean(y)
# calculating the stdandard deviation of y ...
scale_z = np.sqrt(abs(cov[2, 2])) * n_std
mean_z = np.mean(z)

# Radii corresponding to the coefficients:
radii_scaled = [radii[0]*scale_x, radii[1]*scale_y, radii[2]*scale_z]
center = [mean_x,mean_y,mean_z]


# Set of all spherical angles:
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)

# Cartesian coordinates that correspond to the spherical angles:
# (this is the equation of an ellipsoid):
x = radii[0] * np.outer(np.cos(u), np.sin(v))
y = radii[1] * np.outer(np.sin(u), np.sin(v))
z = radii[2] * np.outer(np.ones_like(u), np.cos(v))

for ki in range(len(x)):
    for kj in range(len(x)):
        [x[ki,kj],y[ki,kj],z[ki,kj]] = np.dot([scale_x*x[ki,kj],scale_y*y[ki,kj],scale_z*z[ki,kj]], rotation) + center

# Plot:
ax.plot_surface(x, y, z, alpha=0.2)

def confidence_ellipse(x, y, ax, n_std=3.0, facecolor='none', **kwargs): """ 创建 xy 的协方差置信椭圆图。

Parameters
----------
x, y : array-like, shape (n, )
    Input data.

ax : matplotlib.axes.Axes
    The axes object to draw the ellipse into.

n_std : float
    The number of standard deviations to determine the ellipse's radiuses.

**kwargs
    Forwarded to `~matplotlib.patches.Ellipse`

Returns
-------
matplotlib.patches.Ellipse
"""
if x.size != y.size:
    raise ValueError("x and y must be the same size")

cov = np.cov(x, y)
pearson = cov[0, 1]/np.sqrt(abs(cov[0, 0] * cov[1, 1]))
# Using a special case to obtain the eigenvalues of this
# two-dimensionl dataset.
ell_radius_x = np.sqrt(abs(1 + pearson))
ell_radius_y = np.sqrt(abs(1 - pearson))
ellipse = Ellipse((0, 0), width=ell_radius_x * 2, height=ell_radius_y * 2,
                  facecolor=facecolor, **kwargs)

# Calculating the stdandard deviation of x from
# the squareroot of the variance and multiplying
# with the given number of standard deviations.
scale_x = np.sqrt(abs(cov[0, 0])) * n_std
mean_x = np.mean(x)

# calculating the stdandard deviation of y ...
scale_y = np.sqrt(abs(cov[1, 1])) * n_std
mean_y = np.mean(y)

transf = transforms.Affine2D() \
    .rotate_deg(45) \
    .scale(scale_x, scale_y) \
    .translate(mean_x, mean_y)

ellipse.set_transform(transf + ax.transData)
return ax.add_patch(ellipse)
scipy pca confidence-interval
© www.soinside.com 2019 - 2024. All rights reserved.