如何用Python绘制附带特征向量的二维置信椭圆
协方差置信椭圆+特征向量叠加可视化实现
直接基于numpy+matplotlib即可实现需求,完整可运行代码如下:
依赖安装
pip install numpy matplotlib scipy
核心实现代码
import numpy as np import matplotlib.pyplot as plt from matplotlib.patches import Ellipse from scipy.stats import chi2 def plot_cov_ellipse(cov, center, conf_scale=2, ax=None, **style_kwargs): """ 绘制二维协方差矩阵对应的置信椭圆,同时返回特征值、特征向量用于后续绘制 :param cov: 2*2协方差矩阵 :param center: 椭圆中心坐标,即二维数据的均值点 :param conf_scale: 置信区间缩放系数,由卡方分布分位数计算得到 :param ax: matplotlib坐标轴对象 :param style_kwargs: 椭圆样式参数(边框色、填充色、线宽等) """ # 对协方差矩阵的特征值降序排序,保证长轴对应最大特征值 eig_vals, eig_vecs = np.linalg.eigh(cov) sort_idx = eig_vals.argsort()[::-1] eig_vals, eig_vecs = eig_vals[sort_idx], eig_vecs[:, sort_idx] # 计算椭圆旋转角度(弧度转角度) rotate_angle = np.degrees(np.arctan2(*eig_vecs[:, 0][::-1])) # 计算椭圆宽高:2倍半轴长度 ellipse_width, ellipse_height = 2 * conf_scale * np.sqrt(eig_vals) if ax is None: ax = plt.gca() ellipse = Ellipse( xy=center, width=ellipse_width, height=ellipse_height, angle=rotate_angle, **style_kwargs ) ax.add_patch(ellipse) return eig_vals, eig_vecs # ---------------------- 示例运行 ---------------------- if __name__ == "__main__": # 生成模拟二维正态分布数据 np.random.seed(42) data_mean = [2, 3] data_cov = [[3, 2], [2, 2]] sample_data = np.random.multivariate_normal(data_mean, data_cov, size=1000) x, y = sample_data.T # 初始化画布 fig, ax = plt.subplots(figsize=(8, 8)) # 绘制原始散点 ax.scatter(x, y, s=12, alpha=0.4, label="样本散点") # 从样本计算实际均值和协方差 calc_mean = np.mean(sample_data, axis=0) calc_cov = np.cov(x, y) # 计算95%置信度对应的缩放系数(二维数据自由度为2) conf_level = 0.95 chi2_threshold = chi2.ppf(conf_level, df=2) conf_scale = np.sqrt(chi2_threshold) # 绘制置信椭圆 eig_vals, eig_vecs = plot_cov_ellipse( calc_cov, calc_mean, conf_scale=conf_scale, ax=ax, facecolor="none", edgecolor="#c82423", linewidth=2, label=f"{int(conf_level*100)}%置信椭圆" ) # 叠加绘制特征向量箭头 arrow_length_scale = 2 for idx in range(2): vec_dir = eig_vecs[:, idx] vec_len = np.sqrt(eig_vals[idx]) * arrow_length_scale ax.arrow( calc_mean[0], calc_mean[1], vec_dir[0] * vec_len, vec_dir[1] * vec_len, head_width=0.2, head_length=0.2, fc="#8b0000", ec="#8b0000", label=f"特征向量{idx+1}" ) # 调整显示参数 ax.set_aspect("equal", adjustable="box") ax.legend() ax.set_xlabel("X轴") ax.set_ylabel("Y轴") plt.title("协方差置信椭圆与特征向量可视化") plt.show()
关键注意事项
- 置信度不要直接用固定标准差倍数:2倍标准差仅对应二维正态分布约86%的置信区间,要得到指定置信度的椭圆,必须取自由度为2的卡方分布对应分位数的平方根作为缩放系数,常用置信度对应缩放值为:90%≈2.146、95%≈2.448、99%≈3.035。
- 特征值必须做降序排序,保证椭圆长轴对应最大方差方向,否则会出现角度计算错误。
- 必须将坐标轴宽高比设为
equal,否则椭圆会因坐标轴拉伸出现视觉变形,和实际协方差方向不匹配。 - 特征向量箭头长度和对应特征值的平方根成正比,和椭圆半轴长度对齐,可通过调整
arrow_length_scale参数修改箭头显示长度。
内容的提问来源于stack exchange,提问作者Remz1337
相关产品推荐
相关产品推荐

