Introduction
这是最基本的那张图:两个数值变量,一个点是一次观测。相关系数、回归斜率、以及一切"两个量有关系"的说法,都必须先在这张图上站得住。
correlation_heatmap 那一页反复说"回到散点图确认",说的就是这里。相关系数把一段关系压成一个数,而压缩必然丢东西——丢掉的正是形状:是直是弯、有没有离群点在主导、是不是几个分组各自成团拼出来的假趋势。这些在热图上全都看不见,在这张图上一眼就有。
读的时候按这个顺序:
- 先看形状,别急着看线。 点云是沿一条直线散开,还是拐了个弯、或者分成几团?拟合线画在任何点云上都会出来一条,它不负责告诉你该不该画。
- 看离散程度。 点贴着线还是甩得很开。
r高只说明贴得紧,不说明斜率大;斜率大也不说明贴得紧。这是两件事。 - 找孤立点。 一个远离点云的观测能显著改变斜率和
r,尤其在 x 方向上远的那种(杠杆点)。看到就单独查一下它是什么。 - 看置信带宽度。 两端变宽是正常的——那里数据少。带子宽到能塞进一条水平线,就说明"有没有趋势"这件事本身都还没定。
- 再问一次有没有分组。 这是最容易跳过、也最容易翻车的一步:整体一条趋势,拆开之后可能完全是另一回事。
Example Data
散点图要的输入是:2 个数值变量,同一批观测,一行一个观测;要拆分组再加 1 个分类变量。两个变量必须来自同一行,否则连成对都谈不上。
mtcars 是 R 内置数据,32 辆车,这里看车重(wt)和油耗(mpg)。它已经能直接用,只要把 cyl 转成因子。
library(ggplot2)
library(ggpubr)
library(biopalette)
# mtcars 随 R 一起装好,不用下载
d <- mtcars
# 不转的话 cyl 是数值 4/6/8,会被当成连续量映射成一根渐变色条,
# 而它其实是三个组 —— 图能画出来,只是图例是错的
d$cyl <- factor(d$cyl)
Palettes
分组图使用 three_body 的蓝、绿、橙红。三条拟合线彼此靠得很近,色相差异比同色系的深浅差异更容易辨认;缸数顺序已经直接写在图例标签里,不再让颜色重复承担排序任务。
fit_cols <- get_palette("three_body", type = "qualitative")
cyl_cols <- setNames(fit_cols, c("4", "6", "8"))
# 基础图也沿用同一套色板:点用蓝,拟合线用橙红
POINT <- fit_cols[[1]]
LINE <- fit_cols[[3]]
Recipe
| No. | Method | Input Data | Palettes |
|---|---|---|---|
| 1 | ggplot2 + ggpubr |
d |
POINT / LINE |
| 2 | ggplot2 |
d |
cyl_cols |
1 · 一条拟合线
不分组,先看整体是什么形状。
#| fig: basic
#| fig-width: 7
#| fig-height: 5
ggplot(d, aes(x = wt, y = mpg)) +
geom_point(size = 2.6, alpha = 0.85, color = POINT) +
geom_smooth(
method = "lm", # 必须显式写 —— 默认在 n < 1000 时是 loess,会画出曲线
formula = y ~ x, # 显式给公式,否则每次画图都提示一行 message
se = TRUE, # 置信带:它宽不宽比线本身斜不斜更值得看
color = LINE, fill = LINE, alpha = 0.15, linewidth = 0.9
) +
# r 和 p 直接标在图上,省得读者去别处找
stat_cor(method = "pearson", label.x = 3.8, label.y = 33, size = 4.2) +
labs(
x = "Weight (1000 lbs)", y = "Miles per gallon",
title = "mpg vs wt: mtcars"
) +
theme_pubr(base_size = 12)
