在R语言散点图中添加基于X区间中位数Y的经验最佳拟合线
实现自定义X区间的中位数拟合线(非参数方法)
刚好我之前做过类似的需求,这种非参数的区间中位数拟合线很适合展示数据趋势,而且完全不需要参数拟合,灵活性拉满。下面一步步给你演示怎么实现:
首先,我们先模拟一组匹配你场景的示例数据:
set.seed(123) # 固定随机种子,保证结果可重复 x <- runif(200, min = 0.1, max = 0.3) # 生成0.1到0.3之间的随机X值 y <- 5 + 10*(x - 0.2)^2 + rnorm(200, 0, 0.2) # 带噪声的二次曲线Y值 df <- data.frame(x, y)
第一步:自定义X区间分组
用cut()函数可以轻松实现灵活的区间分组,你可以完全自定义区间的间隔或者断点:
# 这里按0.01的步长划分区间,你可以修改breaks参数调整区间 # 比如想要0.02的步长,就把by改成0.02;非等距区间直接写breaks=c(0.1,0.12,0.15,...) df$x_group <- cut(df$x, breaks = seq(0.1, 0.3, by = 0.01), include.lowest = TRUE)
include.lowest=TRUE是为了确保第一个区间能包含最小的X值,避免数据遗漏。
第二步:计算每个区间的中位数Y和区间中点
我个人习惯用dplyr来做数据汇总,代码更直观;如果你不想加载额外包,也可以用base R实现,我后面也会提。
library(dplyr) fit_data <- df %>% group_by(x_group) %>% summarize( # 提取区间的上下限,然后计算中点 lower = as.numeric(strsplit(gsub("\\(|\\)|\\[|\\]", "", as.character(x_group)), ",")[[1]][1]), upper = as.numeric(strsplit(gsub("\\(|\\)|\\[|\\]", "", as.character(x_group)), ",")[[1]][2]), x_mid = (lower + upper)/2, # 计算该区间内Y值的中位数 y_median = median(y, na.rm = TRUE) ) %>% # 去掉没有数据的区间(避免画图时出现断点) filter(!is.na(y_median)) %>% select(x_mid, y_median) # 只保留需要的列
如果用base R的话,可以这样写:
# Base R 版本的分组计算 x_groups <- unique(df$x_group) fit_data_base <- data.frame(x_mid = numeric(), y_median = numeric()) for (group in x_groups) { group_data <- df[df$x_group == group, ] if (nrow(group_data) == 0) next # 提取区间上下限 interval_str <- gsub("\\(|\\)|\\[|\\]", "", as.character(group)) bounds <- as.numeric(strsplit(interval_str, ",")[[1]]) x_mid <- mean(bounds) y_median <- median(group_data$y, na.rm = TRUE) fit_data_base <- rbind(fit_data_base, data.frame(x_mid, y_median)) }
第三步:画出散点图+中位数拟合线
用ggplot2(美观易调整)
library(ggplot2) ggplot() + # 画原始散点,alpha调小一点避免点重叠 geom_point(data = df, aes(x = x, y = y), alpha = 0.6, color = "steelblue") + # 画中位数拟合线,用红色加粗突出 geom_line(data = fit_data, aes(x = x_mid, y = y_median), color = "red", linewidth = 1.2) + labs(title = "散点图 + 自定义X区间中位数拟合线", x = "X值", y = "Y值") + theme_minimal()
用Base R(轻量无依赖)
plot(df$x, df$y, pch = 16, col = "steelblue", alpha = 0.6, main = "散点图 + 自定义X区间中位数拟合线", xlab = "X值", ylab = "Y值") # 画拟合线 lines(fit_data$x_mid, fit_data$y_median, col = "red", lwd = 2)
这样就能得到你想要的效果:每个X区间的中点对应该区间Y的中位数,连接起来就是一条完全基于数据分布的经验拟合线,而且区间可以随便调整,完全不需要参数拟合~
内容的提问来源于stack exchange,提问作者Stephen Clark
相关产品推荐
相关产品推荐

