如何在ggplot2绘图中还原坐标轴的缩放与中心化处理结果?
问题原因
- 自定义坐标转换的逆转换逻辑错误:原代码使用
scale(x)做逆转换,该函数会基于传入的刻度值重新计算均值和标准差,而非使用你预先存储的原始变量的中心化、缩放参数,导致刻度映射错误。 - 数据类型不兼容:
scale()返回的是矩阵类型而非普通数值向量,和向量运算时触发R的循环复用弃用警告。
解决方案
方案1:修正自定义坐标转换(适合需要连续坐标变换的场景)
直接手动实现正/逆转换逻辑,避免使用scale()函数,代码修改如下:
library('tidyverse') x <- rnorm(100, 10, 1.5) Zx <- scale(x) Zy <- .8*Zx + rnorm(100, 0, sqrt(1 - (.8^2))) df <- tibble(Zx = as.numeric(Zx), y = Zy) # 先把Zx转成普通向量,去掉scale带来的属性 # 提取原始标准化参数,转成普通数值 SD_scale <- as.numeric(attr(Zx, "scaled:scale")) center <- as.numeric(attr(Zx, "scaled:center")) # 定义正确的反标准化转换 unscale_trans <- scales::trans_new( "unscale", transform = function(z) center + z * SD_scale, # 标准化值转原始值(用于显示标签) inverse = function(x) (x - center)/SD_scale # 原始值转标准化值(用于计算刻度位置) ) # 绘图 df %>% ggplot(aes(x=Zx,y=y)) + geom_point() + geom_smooth(method = "lm") + scale_x_continuous(trans = unscale_trans, name = "原始变量数值")
方案2:直接修改刻度标签(更简单,适合绝大多数场景)
不需要修改坐标转换逻辑,仅将x轴的刻度标签做反标准化转换即可,完全避免转换带来的兼容性问题:
library('tidyverse') x <- rnorm(100, 10, 1.5) Zx <- scale(x) Zy <- .8*Zx + rnorm(100, 0, sqrt(1 - (.8^2))) df <- tibble(Zx = Zx, y = Zy) SD_scale <- as.numeric(attr(df$Zx, "scaled:scale")) center <- as.numeric(attr(df$Zx, "scaled:center")) df %>% ggplot(aes(x=Zx,y=y)) + geom_point() + geom_smooth(method = "lm") + scale_x_continuous( name = "原始变量数值", labels = function(z) round(center + z * SD_scale, 2) # 直接把刻度值转成原始值显示 )
两种方案都不会触发警告,且x轴会正常显示原始变量的数值范围,回归拟合结果和使用标准化变量绘图的结果完全一致。
内容的提问来源于stack exchange,提问作者John D. Kirwan
相关产品推荐
相关产品推荐

