Plotly绘制PCA载荷图标注重叠无法阅读 如何调整提升可读性
解决PCA载荷散点图标注重叠的方案
前置修正:解决特征与载荷的匹配错误
你当前的代码存在索引错配问题:你对分类特征做了独热编码,编码后特征维度会远高于原始的19个,直接用原始X的特征名对应编码后的载荷属于逻辑错误,首先需要正确获取编码后的所有特征名:
# 拟合pipeline后获取编码后的完整特征名 encoded_features = pca_pipe.named_steps['columntransformer'].get_feature_names_out() loadings = pca.components_.T * np.sqrt(pca.explained_variance_)
标注防重叠核心优化点
- 放大画布尺寸,给标签留出足够展示空间
- 对载荷端点做小幅外移,避免标签和载荷线重叠
- 给标签添加半透明白色背景,降低互相遮挡的影响
- 根据载荷方向动态调整标签锚点和角度,提升可读性
- (可选)仅展示载荷模长排名前N的特征,减少标签总量
修改后的完整可运行代码
import numpy as np import plotly.express as px from sklearn.decomposition import PCA from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.pipeline import make_pipeline # 原有pipeline逻辑不变 categorical_ix = X.select_dtypes(exclude=np.number).columns ct = ColumnTransformer([ ('encoder', OneHotEncoder(), categorical_ix), ('scaler', StandardScaler(), ['tenure', 'MonthlyCharges', 'TotalCharges']) ], remainder='passthrough') pca_pipe = make_pipeline(ct, PCA(n_components=2)) pca_result = pca_pipe.fit_transform(X) # 修正:获取编码后的正确特征名 pca = pca_pipe.named_steps['pca'] encoded_features = pca_pipe.named_steps['columntransformer'].get_feature_names_out() loadings = pca.components_.T * np.sqrt(pca.explained_variance_) # 放大画布尺寸 fig = px.scatter(pca_result, x=0, y=1, color=customer_data_raw['Churn'], width=1000, height=800) # 载荷缩放系数,可根据实际载荷大小调整,拉大特征间距 load_scale = 3 for i, feature in enumerate(encoded_features): x1, y1 = loadings[i, 0] * load_scale, loadings[i, 1] * load_scale # 绘制载荷线 fig.add_shape( type='line', x0=0, y0=0, x1=x1, y1=y1, line=dict(color='red', width=1) ) # 计算标签角度,顺着载荷线方向 angle = np.arctan2(y1, x1) * 180 / np.pi # 根据象限调整锚点,避免标签压在线上 xanchor = 'left' if x1 > 0 else 'right' yanchor = 'bottom' if y1 > 0 else 'top' fig.add_annotation( x=x1, y=y1, text=feature, showarrow=False, xanchor=xanchor, yanchor=yanchor, textangle=angle if abs(angle) < 90 else angle + 180, # 保证文字正向可读 font=dict(size=9), bgcolor='rgba(255,255,255,0.7)', # 半透明白色背景降低遮挡 borderpad=2 ) # 开启全局防重叠配置 fig.update_layout( uniformtext_minsize=8, uniformtext_mode='show', xaxis_title='PC1', yaxis_title='PC2' ) fig.show()
如果标签还是较多,可在循环前添加过滤逻辑,仅保留载荷模长最大的前15个特征标注:
# 计算每个特征的载荷模长 loading_magnitude = np.linalg.norm(loadings, axis=1) # 取模长前15的特征索引,数字可按需调整 top_idx = loading_magnitude.argsort()[-15:] # 循环仅遍历top_idx即可 for i in top_idx: feature = encoded_features[i] # 剩余绘制逻辑和上文一致
内容的提问来源于stack exchange,提问作者LeLuc
相关产品推荐
相关产品推荐

