当使用 StandardScaler 对特征进行标准化后训练模型并绘制部分依赖图时,x轴显示的是缩放后的数值,影响业务可解释性;本文介绍如何通过反向变换刻度标签,将PDP横轴恢复为原始数据单位,无需重拟合模型或修改内部计算逻辑。
先直接说结论:用 StandardScaler 标准化数据训练完随机森林这类模型后,直接调用 PartialDependenceDisplay.from_estimator() 画出来的部分依赖图(PDP),横坐标上跑的是标准化后的数值——比如 -1.2 到 2.4 这种,而不是业务人员一眼就能看懂的 35.6℃ 或 8200 元。这图拿到业务会上,基本等于白画。
问题的核心在于:PDP 的计算依赖模型对输入数据的预测行为,而模型只认标准化后的数据。所以不能简单地把 X_test_final 反标准化后再喂给绘图函数——那样预测会完全失效。正确的解法是:保持模型输入的标准化流程不变,只对可视化端的坐标轴刻度标签做逆变换。这样既不影响模型逻辑,又能让横轴回归到原始单位。
具体操作分三步,不复杂:
先画出原始 PDP,同时拿到坐标轴对象:
import matplotlib.pyplot as plt from sklearn.inspection import PartialDependenceDisplay fig, ax = plt.subplots(figsize=(8, 6)) display = PartialDependenceDisplay.from_estimator( best_clf, X_test_final, best_features, ax=ax )对 x 轴刻度做逆标准化(反 StandardScaler):
假设你训练时保存了 StandardScaler 实例(强烈推荐这么做),或者能从原始训练集
X_train中重新算出均值和标准差:# ✅ 推荐:用训练时保存的 scaler(确保一致性) # scaler = StandardScaler().fit(X_train) # mean_val = scaler.mean_[feature_idx] # std_val = scaler.scale_[feature_idx] # 如果没保存 scaler,且 X_train 是原始训练集(二维数组),按特征索引提取: feature_idx = 0 # 替换成你要可视化的特征在 X_train 中的列索引 mean_val = X_train[:, feature_idx].mean() std_val = X_train[:, feature_idx].std() # 获取当前 x 轴刻度位置(标准化尺度) x_ticks = ax.get_xticks() # 逆变换:X_original = X_scaled × std + mean xticks_unscaled = [(xt * std_val) + mean_val for xt in x_ticks] # 格式化成易读字符串(保留1位小数,或根据数据本身调整) ax.set_xticklabels([f'{val:.1f}' for val in xticks_unscaled])完善图表并展示:
ax.set_xlabel(f'{feature_name} (original scale)') # 加上单位说明 plt.tight_layout() plt.show()
⚠️ 需要留意的几个点:
- 刻度逆变换只影响标签显示,PDP 曲线的形状和计算逻辑没有任何变动,完全安全;
- 计算 mean 和 std 时务必用训练集,而不是测试集——这符合 StandardScaler 的设计原则;
- 如果
best_features包含多个特征,要分别对每个子图处理对应的mean_val和std_val; - 类别型特征或经过 One-Hot 编码等预处理的特征,这个方法不适用,需要单独处理。
用这个思路,你既能保留标准化建模流程的高效和稳定,又能输出业务人员一看就懂的部分依赖图——建模和解释,算是真正解耦了。