You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ggplot2中geom_smooth使用x~y公式报错问题求助

解决ggplot2中geom_smooth使用x~y公式报错的问题

在使用ggplot2绘制父子身高回归关系时,尝试将geom_smooth的公式从y~x改为x~y以绘制X对Y的回归线(即父亲身高对儿子身高的反向回归),但运行代码时报错,无法得到预期的双回归线效果。

原报错代码

library(ggplot2)
library(tidyverse)
library(MASS)

N <- 10000
mu = 175.9   #cm -- 英国成年男性身高
sigma = 6.35 #cm -- 英国成年男性身高
rho <- 0.5   # 父子身高相关系数

pts <- mvrnorm(n = N, mu = c(mu, mu), Sigma = sigma ^ 2 * matrix(c(1, rho, rho, 1), ncol = 2))
df <- tibble(father = pts[,1], son = pts[,2])

ggplot(df, aes(x=father, y=son)) + 
  theme(aspect.ratio = 1) + 
  xlim(150, 202) + 
  ylim(150, 202) + 
  labs(title = "英国父子成年身高关系", x = "X = 父亲身高(cm)", y = "Y = 儿子身高(cm)") +
  geom_point(shape = '.', alpha = 0.1, na.rm = TRUE) +  
  geom_smooth(method='lm', formula = y~x, linewidth=.3, colour = 'blue', na.rm = TRUE) + 
  annotate("text", x = 191, y = 186, angle = 26, colour = 'blue', label = 'Y对X的回归线') +
  geom_smooth(method='lm', formula = x~y, linewidth=.3, colour = 'red', na.rm = TRUE) + 
  annotate("text", x = 186, y = 191, angle = 90 - 26, colour = 'red', label = 'X对Y的回归线')

报错原因

geom_smooth默认遵循ggplot设定的aes(x=father, y=son)映射,拟合逻辑是生成y关于x的预测值。当直接使用formula = x~y时,模型会尝试拟合x(father)关于y(son)的回归,但geom_smooth仍会用原x轴的取值去生成预测结果,这与坐标系的映射逻辑冲突,导致维度不匹配或预测逻辑错误,最终报错。

解决方案

有两种可靠方法可以实现绘制X对Y的回归线:

方法1:临时交换x和y的映射

在第二个geom_smooth中临时替换x和y的映射关系,保持公式为y~x,让模型拟合father(作为y)关于son(作为x)的回归,绘制结果即为原坐标系中X对Y的回归线。

修改后代码:

library(ggplot2)
library(tidyverse)
library(MASS)

N <- 10000
mu = 175.9   #cm -- 英国成年男性身高
sigma = 6.35 #cm -- 英国成年男性身高
rho <- 0.5   # 父子身高相关系数

pts <- mvrnorm(n = N, mu = c(mu, mu), Sigma = sigma ^ 2 * matrix(c(1, rho, rho, 1), ncol = 2))
df <- tibble(father = pts[,1], son = pts[,2])

ggplot(df, aes(x=father, y=son)) + 
  theme(aspect.ratio = 1) + 
  xlim(150, 202) + 
  ylim(150, 202) + 
  labs(title = "英国父子成年身高关系", x = "X = 父亲身高(cm)", y = "Y = 儿子身高(cm)") +
  geom_point(shape = '.', alpha = 0.1, na.rm = TRUE) +  
  geom_smooth(method='lm', formula = y~x, linewidth=.3, colour = 'blue', na.rm = TRUE) + 
  annotate("text", x = 191, y = 186, angle = 26, colour = 'blue', label = 'Y对X的回归线') +
  # 临时交换x和y的映射,拟合father关于son的回归
  geom_smooth(aes(x=son, y=father), method='lm', formula = y~x, linewidth=.3, colour = 'red', na.rm = TRUE) + 
  annotate("text", x = 186, y = 191, angle = 90 - 26, colour = 'red', label = 'X对Y的回归线')

方法2:手动计算回归参数,用geom_abline绘制

先计算X对Y的回归模型,将模型参数转换为geom_abline所需的截距和斜率,直接绘制直线,这种方法更直观,也避免了映射冲突。

修改后代码:

library(ggplot2)
library(tidyverse)
library(MASS)

N <- 10000
mu = 175.9   #cm -- 英国成年男性身高
sigma = 6.35 #cm -- 英国成年男性身高
rho <- 0.5   # 父子身高相关系数

pts <- mvrnorm(n = N, mu = c(mu, mu), Sigma = sigma ^ 2 * matrix(c(1, rho, rho, 1), ncol = 2))
df <- tibble(father = pts[,1], son = pts[,2])

# 计算X对Y的回归模型(father ~ son)
fit_x_on_y <- lm(father ~ son, data = df)
# 转换为geom_abline所需的参数:y = intercept + slope*x
abline_intercept <- -coef(fit_x_on_y)[[1]] / coef(fit_x_on_y)[[2]]
abline_slope <- 1 / coef(fit_x_on_y)[[2]]

ggplot(df, aes(x=father, y=son)) + 
  theme(aspect.ratio = 1) + 
  xlim(150, 202) + 
  ylim(150, 202) + 
  labs(title = "英国父子成年身高关系", x = "X = 父亲身高(cm)", y = "Y = 儿子身高(cm)") +
  geom_point(shape = '.', alpha = 0.1, na.rm = TRUE) +  
  geom_smooth(method='lm', formula = y~x, linewidth=.3, colour = 'blue', na.rm = TRUE) + 
  annotate("text", x = 191, y = 186, angle = 26, colour = 'blue', label = 'Y对X的回归线') +
  # 绘制X对Y的回归线
  geom_abline(intercept = abline_intercept, slope = abline_slope, linewidth=.3, colour = 'red') +
  annotate("text", x = 186, y = 191, angle = 90 - 26, colour = 'red', label = 'X对Y的回归线')

两种方法都能得到预期的双回归线效果,同时显示Y对X(儿子身高对父亲身高)和X对Y(父亲身高对儿子身高)的两条回归直线。

内容的提问来源于stack exchange,提问作者Mohan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 04:00:58