数据挖掘与R语言

第7讲:数据可视化 ~ Part 1

2026年04月09日

上讲回顾

  • 替换字段数据mutate() 覆盖同名列;if_else() / case_when() 条件替换;str_replace() 字符串替换;as.*() 类型转换;across() 批量处理多列
  • 处理缺失值drop_na() 删行;replace_na() 固定值填充;fill() 前/后值填充;分组均值填充——无万能策略,理解业务含义是前提
  • 行列合并bind_rows() 纵向堆叠;bind_cols() 横向拼接(需行序严格对应)
  • 表连接left_join() / inner_join() / full_join() 基于键列匹配;anti_join() 找差集;semi_join() 过滤但不附加列
  • table():base R 快速列联表;prop.table() 转比例;addmargins() 加合计
  • 实用技巧distinct() 去重;coalesce() 取第一个非 NA;across(.names=) 不覆盖原列批量操作

本讲内容

  • Part 1:为什么可视化? ——图形的力量(约5分钟)
  • Part 2:base R 作图 ——plot()hist()barplot() 快速入门(约10分钟)
  • Part 3:ggplot2 的语法逻辑 ——图层、映射与几何对象(约15分钟)
  • Part 4:分类变量的可视化 ——条形图与频率图(约15分钟)
  • Part 5:数值变量的可视化 ——直方图、密度图、箱线图(约20分钟)
  • Part 6:双变量关系的可视化 ——散点图、分组条形图、小提琴图(约20分钟)
  • Part 7:多变量扩展 ——颜色、分面与简单美化(约15分钟)

提示

可视化是数据分析中最直接、最有说服力的表达方式。本讲聚焦"用对图"——不同数据类型选什么图;下一讲聚焦"画好图"——主题、标注、配色与发布。

Part 1 为什么可视化?

图形的力量

1.1 Anscombe 四重奏:数字会撒谎,图不会

四组数据,统计摘要几乎完全相同:

# A tibble: 4 × 7
  组        n 均值_x 均值_y 方差_x 方差_y 相关系数
  <chr> <int>  <dbl>  <dbl>  <dbl>  <dbl>    <dbl>
1 1        11      9    7.5     11   4.13     0.82
2 2        11      9    7.5     11   4.13     0.82
3 3        11      9    7.5     11   4.12     0.82
4 4        11      9    7.5     11   4.12     0.82

重要

同样的均值、方差、相关系数——只有作图才能发现真相。可视化不是分析的装饰,而是分析本身。

1.2 可视化的两个核心用途

探索性可视化(EDA)

  • 对象:分析师自己
  • 目的:快速理解数据——找分布、看异常、发现规律
  • 标准:快、准、够用即可
  • 工具:base R 或 ggplot2 默认设置

展示性可视化(Communication)

  • 对象:读者、观众、决策者
  • 目的:清晰传达结论,支持决策
  • 标准:美观、信息密度高、自我解释
  • 工具:ggplot2 精细调整

1.3 如何选择图表类型?

Part 2 base R 作图

快速探索的内置工具

2.1 plot():万能的散点图

plot() 是 base R 最核心的作图函数,根据输入类型自动选择图形:

▶️ 查看代码
# 两个数值向量 → 散点图
plot(mtcars$wt, mtcars$mpg,
     main = "车重 vs 油耗",
     xlab = "车重(千磅)",
     ylab = "油耗(mpg)",
     pch  = 16,          # 实心圆点
     col  = "#1a3a5c")

注记

pch 控制点的形状(16 = 实心圆),col 控制颜色,main/xlab/ylab 设置标题和轴标签。这几个参数几乎适用于所有 base R 图形函数。

2.2 hist():直方图

▶️ 查看代码
hist(mtcars$mpg,
     breaks = 10,          # 分箱数量(约)
     col    = "#4472C4",
     border = "white",
     main   = "汽车油耗分布",
     xlab   = "油耗(mpg)",
     ylab   = "频次")

▶️ 查看代码
# freq = FALSE → 纵轴改为密度(面积 = 1)
hist(mtcars$mpg, freq = FALSE, col = "#4472C4", border = "white",
     main = "油耗分布(密度)", xlab = "mpg")
lines(density(mtcars$mpg), col = "red", lwd = 2)  # 叠加密度曲线

2.3 barplot():条形图

▶️ 查看代码
# table() 生成频率表后直接传给 barplot()
counts <- table(mtcars$cyl)

barplot(counts,
        col    = c("#4472C4", "#ED7D31", "#A9D18E"),
        main   = "各气缸数车辆数量",
        xlab   = "气缸数",
        ylab   = "数量",
        border = NA)

2.4 boxplot():箱线图

▶️ 查看代码
# 公式语法:y ~ 分组变量
boxplot(mpg ~ cyl, data = mtcars,
        col    = c("#4472C4", "#ED7D31", "#A9D18E"),
        main   = "不同气缸数的油耗分布",
        xlab   = "气缸数",
        ylab   = "油耗(mpg)",
        border = "#333333")

2.5 base R 作图:优缺点总结

优点

  • ✅ 无需安装任何包,开箱即用
  • ✅ 代码极简,探索时很快
  • ✅ 与 R 基础函数无缝配合(如 table()lm() 后直接 plot()
  • ✅ 精细控制底层绘图参数(par()

缺点

  • ❌ 语法不一致,不同函数参数名各异
  • ❌ 图层叠加麻烦(需手动 lines()points()……)
  • ❌ 默认美观度较低,精修费时
  • ❌ 分面(多子图)需要手动 par(mfrow=...) 布局

提示

实用建议:用 base R 做快速探索(一行代码,马上出图);用 ggplot2 做展示输出(语法统一,美观易扩展)。两者不是替代关系,而是互补。

Part 3 ggplot2 的语法逻辑

图层、映射与几何对象

3.1 ggplot2 的核心思想:图形语法

ggplot2 基于 Leland Wilkinson 的图形语法(Grammar of Graphics)——每张图都是若干图层的叠加:

▶️ 查看代码
ggplot(data = 数据框,              # ① 数据
       mapping = aes(x = , y = )) + # ② 映射:变量 → 视觉属性
  geom_点线面() +                   # ③ 几何对象:决定图的类型
  scale_*() +                       # ④ 标度:控制映射的细节
  labs() +                          # ⑤ 标签:标题、轴名
  theme_*()                         # ⑥ 主题:整体外观

重要

+ 是 ggplot2 的图层叠加符,不能换成 |>。每一行用 + 连接,代表"在这张图上再加一层"。+ 必须写在行尾,不能写在行首。

3.2 aes():美学映射——变量如何变成视觉

aes() 将数据列映射到图形的视觉通道(aesthetic):

视觉通道 参数 适用变量
x 轴位置 x = 数值 / 分类
y 轴位置 y = 数值 / 分类
颜色(外框/线) color = 分类 / 数值
填充颜色 fill = 分类 / 数值
点的大小 size = 数值
点/线的形状 shape = 分类
透明度 alpha = 数值(0–1)
▶️ 查看代码
# 映射 vs 固定:映射写在 aes() 里,固定值写在 aes() 外
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3, alpha = 0.8)
#                ↑固定        ↑固定(所有点都一样)
#                             color 在 aes() 内 → 按 cyl 自动上色

3.3 第一张 ggplot2 图

▶️ 查看代码
mtcars |> 
  ggplot(mapping = aes(x = wt, y = mpg)) +
  geom_point()

注记

这是最简单的一张散点图:提供数据、设定 x/y 映射、选择几何对象 geom_point()。其余(坐标轴范围、颜色、主题)全部使用 ggplot2 的默认值。

3.4 图层是可以叠加的

▶️ 查看代码
mtcars |> 
  ggplot(aes(x = wt, y = mpg)) +
  geom_point(color = "#1a3a5c", size = 2.5) +    # 第一层:散点
  geom_smooth(method = "lm", se = TRUE,           # 第二层:回归线 + 置信区间
              color = "#e05c2a", fill = "#e05c2a", alpha = 0.15) +
  labs(title  = "车重越大,油耗越低",
       x = "车重(千磅)", y = "油耗(mpg)")

提示

geom_smooth(method = "lm") 自动拟合线性回归线,se = TRUE(默认)显示 95% 置信区间阴影。这两层的 aes() 继承自 ggplot() 中的全局映射——不需要重复写。

Part 4 分类变量的可视化

条形图与频率图

4.1 geom_bar():单变量条形图

geom_bar() 自动计数——只需提供 x 变量,无需预先 count()

▶️ 查看代码
mpg |> 
  ggplot(aes(x = class)) +
  geom_bar(fill = "#1a3a5c") +
  labs(title = "各车型数量",
       x = "车型", y = "数量")

注记

mpg 是 ggplot2 内置数据集,记录 234 辆汽车的燃油效率。geom_bar() 等价于先 count() 再作图,内部调用 stat_count() 自动完成计数。

4.2 geom_col():已有计数时用这个

当数据已经是汇总好的计数/均值时,用 geom_col()(需同时提供 x 和 y):

▶️ 查看代码
mpg |>
  count(class, sort = TRUE) |>
  ggplot(aes(x = n, y = reorder(class, n))) +   # reorder:按 n 排序
  geom_col(fill = "#1a3a5c") +
  labs(title = "各车型数量(降序排列)",
       x = "数量", y = NULL)

提示

reorder(因子列, 排序依据) 是让条形图按数值大小排序的最简洁写法。将 x/y 互换(横向条形图)读起来往往更清晰,尤其是类别名称较长时。

4.3 添加数值标签:geom_text() / geom_label()

▶️ 查看代码
mpg |>
  count(class, sort = TRUE) |>
  ggplot(aes(x = reorder(class, n), y = n)) +
  geom_col(fill = "#4472C4") +
  geom_text(aes(label = n),               # 在每个条形上方显示数字
            vjust = -0.4, size = 3.5,
            fontface = "bold") +
  labs(title = "各车型数量", x = NULL, y = "数量") +
  ylim(0, 70)

4.4 百分比条形图:先转换再作图

▶️ 查看代码
mpg |>
  count(class) |>
  mutate(pct = n / sum(n),
         pct_label = scales::percent(pct, accuracy = 1)) |>
  ggplot(aes(x = pct, y = reorder(class, pct))) +
  geom_col(fill = "#1a3a5c") +
  geom_text(aes(label = pct_label), hjust = -0.2, size = 3.5) +
  scale_x_continuous(labels = scales::percent, limits = c(0, 0.25)) +
  labs(title = "各车型占比", x = "占比", y = NULL)

注记

scales::percent() 将小数格式化为百分比字符串(如 0.15"15%")。scales 包随 ggplot2 一起安装,无需单独 install.packages(),但需要 scales:: 前缀或 library(scales) 后直接调用。

4.5 坐标翻转:coord_flip() vs 交换 x/y

▶️ 查看代码
# 交换 x/y(推荐方式,现代 ggplot2)
mpg |> 
  count(class) |>
  ggplot(aes(x = n, y = class)) +
  geom_col(fill = "#1a3a5c") +
  labs(title = "交换 x/y", x = "数量", y = NULL)
# coord_flip()(旧写法,仍然有效)
mpg |> 
  count(class) |>
  ggplot(aes(x = class, y = n)) +
  geom_col(fill = "#4472C4") +
  coord_flip() +
  labs(title = "coord_flip()", x = NULL, y = "数量")

Part 5 数值变量的可视化

直方图、密度图、箱线图

5.1 geom_histogram():直方图

直方图展示数值变量的频率分布——最常用的探索工具之一:

▶️ 查看代码
mpg |> 
  ggplot(aes(x = hwy)) +
  geom_histogram(binwidth = 3,          # 每个区间的宽度(单位同 x)
                 fill = "#1a3a5c",
                 color = "white") +     # 边框颜色
  labs(title = "高速公路油耗分布",
       x = "油耗(mpg)", y = "车辆数量")

注记

binwidth(区间宽度)是直方图最重要的参数,没有通用最优值。经验法则:先用 bins = 30(默认),再根据分布形态调整。太少的箱会掩盖细节,太多会产生噪音。

5.2 bins 参数的影响

▶️ 查看代码
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 5, fill = "#1a3a5c", color = "white") +
  labs(title = "bins = 5(太粗)", x = "hwy", y = NULL)
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 20, fill = "#1a3a5c", color = "white") +
  labs(title = "bins = 20(合适)", x = "hwy", y = NULL)
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 80, fill = "#1a3a5c", color = "white") +
  labs(title = "bins = 80(太细)", x = "hwy", y = NULL)

提示

没有"正确"的 bins 值——目标是如实呈现分布形态。实践中多试几个值,选最能讲清楚故事的那个。

5.3 geom_density():密度图

密度图是直方图的平滑版本,适合比较多组分布时使用:

▶️ 查看代码
mpg |> 
  ggplot(aes(x = hwy)) +
  geom_density(fill = "#1a3a5c",
               alpha = 0.6,           # 半透明填充
               color = "#0d2238") +
  labs(title = "高速公路油耗密度分布",
       x = "油耗(mpg)", y = "密度")

注记

密度曲线下面积 = 1(概率密度),纵轴单位不是频次而是密度。bw(带宽)参数控制平滑程度,默认由核密度估计算法自动选择。

5.4 直方图 + 密度曲线叠加

▶️ 查看代码
mpg |>
  ggplot(aes(x = hwy)) +
  geom_histogram(aes(y = after_stat(density)),   # 纵轴改为密度(与密度曲线同单位)
                 binwidth = 2,
                 fill = "#4472C4", color = "white", alpha = 0.7) +
  geom_density(color = "#e05c2a",
               linewidth = 1.2) +
  labs(title = "直方图 + 密度曲线",
       x = "高速公路油耗(mpg)", y = "密度")

注记

叠加时直方图纵轴必须改为 after_stat(density),否则密度曲线(数值极小)会被压扁在底部,看不见。after_stat() 是 ggplot2 3.x 的新写法,替代旧版的 stat(density)..density..

5.5 geom_boxplot():箱线图

箱线图用五个统计量概括分布——最小值(非异常值)、Q1、中位数、Q3、最大值,以及超出范围的异常值:

▶️ 查看代码
mpg |> 
  ggplot(aes(y = hwy)) +
  geom_boxplot(fill = "#4472C4",
               color = "#1a3a5c",
               outlier.color = "#e05c2a",
               outlier.size  = 2.5,
               width = 0.4) +
  labs(title = "高速公路油耗箱线图",
       y = "油耗(mpg)") +
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank())

5.6 箱线图的结构解读

Part 6 双变量关系的可视化

散点图、分组条形图、小提琴图

6.1 geom_point():散点图(数值 × 数值)

散点图是展示两个数值变量之间关系的首选:

▶️ 查看代码
mpg |> 
  ggplot(aes(x = displ, y = hwy)) +
  geom_point(color = "#1a3a5c",
             alpha = 0.6,
             size  = 2.5) +
  labs(title = "发动机排量越大,油耗越低",
       x = "发动机排量(升)",
       y = "高速公路油耗(mpg)")

6.2 散点图 + 趋势线

▶️ 查看代码
mpg |> 
  ggplot(aes(x = displ, y = hwy)) +
  geom_point(alpha = 0.5, color = "#1a3a5c", size = 2) +
  geom_smooth(method = "lm",    se = TRUE,   # 线性趋势
              color  = "#e05c2a", fill = "#e05c2a", alpha = 0.15,
              linewidth = 1) +
  labs(title  = "排量与油耗的线性关系(lm 拟合)",
       x = "发动机排量(升)",
       y = "高速公路油耗(mpg)")

提示

method 还可以设为 "loess"(局部加权平滑,默认,捕捉非线性关系)或 "gam"(广义加法模型)。数据量 < 1000 时默认用 loess,≥ 1000 时默认用 gam

6.3 geom_jitter():处理点重叠

当数据点大量重叠时(尤其是分类 × 数值),用 geom_jitter() 添加随机抖动:

▶️ 查看代码
# 纯散点图:点重叠严重
mpg |> 
  ggplot(aes(x = class, y = hwy)) +
  geom_point(color = "#1a3a5c") +
  labs(title = "geom_point(重叠)", x = NULL, y = "油耗")
# 抖动图:清晰展示每个观测
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_jitter(width = 0.2, alpha = 0.6,
              color = "#1a3a5c", size = 2) +
  labs(title = "geom_jitter(抖动)", x = NULL, y = "油耗")

6.4 分组条形图(分类 × 分类)

fill 映射第二个分类变量,position = "dodge" 并排显示:

▶️ 查看代码
mpg |>
  count(class, drv) |>
  ggplot(aes(x = class, y = n, fill = drv)) +
  geom_col(position = "dodge") +
  labs(title = "各车型 × 驱动方式的数量分布",
       x = "车型", y = "数量", fill = "驱动方式")

6.5 堆叠条形图与百分比堆叠

▶️ 查看代码
# 堆叠条形图(position = "stack",默认)
mpg |> count(class, drv) |>
  ggplot(aes(x = class, y = n, fill = drv)) +
  geom_col(position = "stack") +
  labs(title = "堆叠", x = NULL, y = "数量", fill = "驱动")
# 百分比堆叠(position = "fill")
mpg |> count(class, drv) |>
  ggplot(aes(x = class, y = n, fill = drv)) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "百分比堆叠", x = NULL, y = "占比", fill = "驱动")

注记

position 效果 适用场景
"dodge" 并排 比较绝对数量
"stack" 堆叠 显示整体与部分
"fill" 百分比堆叠 比较组内构成比例

6.6 geom_boxplot():分组箱线图(分类 × 数值)

▶️ 查看代码
mpg |> 
  ggplot(aes(x = class, y = hwy, fill = class)) +
  geom_boxplot(show.legend = FALSE,
               outlier.alpha = 0.5) +
  labs(title = "不同车型的高速公路油耗分布",
       x = "车型", y = "油耗(mpg)")

提示

fill 映射到 x 变量(fill = class)能自动给每个组上色,增加视觉区分度。show.legend = FALSE 避免图例重复出现。

6.7 geom_violin():小提琴图

小提琴图 = 箱线图 + 密度信息,同时展示分布的形状(峰、谷、长尾):

▶️ 查看代码
mpg |> 
  ggplot(aes(x = class, y = hwy, fill = class)) +
  geom_violin(show.legend = FALSE,
              alpha = 0.7,
              trim  = FALSE) +    # trim = FALSE:尾部不截断
  labs(title = "各车型油耗分布(小提琴图)",
       x = "车型", y = "油耗(mpg)")

6.8 小提琴图 + 箱线图叠加

▶️ 查看代码
ggplot(mpg, aes(x = class, y = hwy, fill = class)) +
  geom_violin(alpha = 0.5, show.legend = FALSE, trim = FALSE) +
  geom_boxplot(width = 0.15,                # 细箱线压在小提琴上
               fill  = "white",
               outlier.size = 1.5,
               show.legend  = FALSE) +
  labs(title = "小提琴图 + 箱线图叠加:形状 + 五数概括一次呈现",
       x = "车型", y = "油耗(mpg)")

提示

叠加顺序很重要:先画 geom_violin(),再画 geom_boxplot(),箱线图才能覆盖在小提琴上面。width = 0.15 让箱线图足够细,不遮挡小提琴的轮廓。

Part 7 多变量扩展

颜色、分面与简单美化

7.1 颜色映射:第三个维度

在散点图中,将第三个变量映射到 color(分类)或 size(数值),可以同时展示三个变量的关系:

▶️ 查看代码
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(title = "排量、油耗与车型",
       x = "发动机排量(升)",
       y = "高速公路油耗(mpg)",
       color = "车型")

7.2 shapesize 映射

▶️ 查看代码
# color + shape 双重映射(黑白打印友好)
ggplot(mpg, aes(x = displ, y = hwy,
                color = drv, shape = drv)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(title = "color + shape 双重映射",
       x = "排量", y = "油耗", color = "驱动", shape = "驱动")
# size 映射数值变量
ggplot(mpg, aes(x = displ, y = hwy,
                color = class, size = cyl)) +
  geom_point(alpha = 0.6) +
  labs(title = "size 映射气缸数",
       x = "排量", y = "油耗",
       color = "车型", size = "气缸")

7.3 facet_wrap():单变量分面

分面(facet)将数据按某个变量拆分,在多个子图中分别绘制——是比颜色映射更清晰的多变量展示方式:

▶️ 查看代码
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(color = "#1a3a5c", alpha = 0.6, size = 1.8) +
  geom_smooth(method = "lm", se = FALSE,
              color = "#e05c2a", linewidth = 0.8) +
  facet_wrap(~ drv,            # 按 drv 列分面
             nrow = 1,         # 排成一行
             labeller = labeller(drv = c("4" = "四驱", "f" = "前驱", "r" = "后驱"))) +
  labs(title = "不同驱动方式下:排量与油耗的关系",
       x = "发动机排量(升)", y = "油耗(mpg)")

7.4 facet_grid():双变量分面

facet_grid()两个变量形成行列矩阵分面:

▶️ 查看代码
mpg |>
  filter(class %in% c("compact", "suv", "pickup")) |>
  ggplot(aes(x = displ, y = hwy)) +
  geom_point(aes(color = class), alpha = 0.7, size = 2,
             show.legend = FALSE) +
  geom_smooth(method = "lm", se = FALSE,
              color = "#333333", linewidth = 0.8) +
  facet_grid(drv ~ class) +    # 行:drv,列:class
  labs(title = "分面矩阵:驱动方式(行)× 车型(列)",
       x = "发动机排量(升)", y = "高速公路油耗(mpg)")

7.5 常用主题:theme_*()

ggplot2 内置多种主题,一行代码改变整体风格:

▶️ 查看代码
p <- ggplot(mpg, aes(x = class)) + geom_bar(fill = "#1a3a5c") +
     labs(x = NULL, y = NULL)

p + theme_gray()    + labs(title = "theme_gray()(默认)")
p + theme_minimal() + labs(title = "theme_minimal()")
p + theme_classic() + labs(title = "theme_classic()")

注记

其他常用主题:theme_bw()(黑白网格)、theme_light()(浅灰网格)、theme_dark()(深色背景)、theme_void()(无背景)。学术论文通常用 theme_classic()theme_bw()

7.6 用 labs() 完善图形信息

labs() 是添加所有文字标注的统一入口:

▶️ 查看代码
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 2.5, alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.8) +
  labs(
    title    = "发动机排量越大,油耗越低——后驱车下降最明显",  # 主标题
    subtitle = "数据来源:ggplot2 内置 mpg 数据集,234 辆 1999–2008 年车型",
    x        = "发动机排量(升)",
    y        = "高速公路油耗(英里/加仑)",
    color    = "驱动方式",
    caption  = "注:4 = 四驱,f = 前驱,r = 后驱"  # 图注
  ) +
  theme_minimal(base_size = 11)

综合实战

从数据到图形的完整流程

综合实战:diamonds 数据集探索

diamonds 是 ggplot2 内置数据集,含 53,940 颗钻石的价格与属性。

▶️ 查看代码
glimpse(diamonds)
Rows: 53,940
Columns: 10
$ carat   <dbl> 0.23, 0.21, 0.23, 0.29, 0.31, 0.24, 0.24, 0.26, 0.22, 0.23, 0.…
$ cut     <ord> Ideal, Premium, Good, Premium, Good, Very Good, Very Good, Ver…
$ color   <ord> E, E, E, I, J, J, I, H, E, H, J, J, F, J, E, E, I, J, J, J, I,…
$ clarity <ord> SI2, SI1, VS1, VS2, SI2, VVS2, VVS1, SI1, VS2, VS1, SI1, VS1, …
$ depth   <dbl> 61.5, 59.8, 56.9, 62.4, 63.3, 62.8, 62.3, 61.9, 65.1, 59.4, 64…
$ table   <dbl> 55, 61, 65, 58, 58, 57, 57, 55, 61, 61, 55, 56, 61, 54, 62, 58…
$ price   <int> 326, 326, 327, 334, 335, 336, 336, 337, 337, 338, 339, 340, 34…
$ x       <dbl> 3.95, 3.89, 4.05, 4.20, 4.34, 3.94, 3.95, 4.07, 3.87, 4.00, 4.…
$ y       <dbl> 3.98, 3.84, 4.07, 4.23, 4.35, 3.96, 3.98, 4.11, 3.78, 4.05, 4.…
$ z       <dbl> 2.43, 2.31, 2.31, 2.63, 2.75, 2.48, 2.47, 2.53, 2.49, 2.39, 2.…
▶️ 查看代码
# 切割质量分布(分类变量)
diamonds |>
  count(cut) |>
  ggplot(aes(x = n, y = reorder(cut, n))) +
  geom_col(fill = "#1a3a5c") +
  geom_text(aes(label = scales::comma(n)), hjust = -0.1, size = 3.2) +
  xlim(0, 25000) +
  labs(title = "各切割质量的钻石数量", x = "数量", y = "切割质量") +
  theme_minimal()
# 价格分布(数值变量)
ggplot(diamonds, aes(x = price)) +
  geom_histogram(bins = 50, fill = "#4472C4", color = "white") +
  scale_x_continuous(labels = scales::dollar) +
  labs(title = "钻石价格分布(右偏)", x = "价格(美元)", y = "数量") +
  theme_minimal()

综合实战(续):多变量关系

▶️ 查看代码
# 克拉数 vs 价格,按切割质量分面
diamonds |>
  sample_n(3000) |>                          # 随机取样,加快渲染
  ggplot(aes(x = carat, y = price, color = cut)) +
  geom_point(alpha = 0.4, size = 1.2) +
  geom_smooth(method = "lm", se = FALSE,
              linewidth = 0.8) +
  scale_y_continuous(labels = scales::dollar) +
  scale_color_brewer(palette = "Set1") +
  facet_wrap(~ cut, nrow = 1) +
  labs(title  = "克拉数与价格的关系——按切割质量分面",
       x = "克拉数", y = "价格(美元)",
       color = "切割质量") +
  theme_minimal(base_size = 10) +
  theme(legend.position = "none")

本讲小结

  • 为什么可视化:Anscombe 四重奏揭示了数字统计掩盖真相的风险;可视化分为探索性(EDA)与展示性两种用途,ggplot2 对两者都适用

  • base R 作图plot()hist()barplot()boxplot() 无需加载包,适合快速探索;语法不统一、默认美观度低是其主要局限

  • ggplot2 语法逻辑:数据 + aes() 映射 + geom_*() 几何对象 = 一张图;图层用 + 叠加;aes() 内是映射(按变量变化),aes() 外是固定值

  • 分类变量geom_bar()(自动计数)/ geom_col()(已有计数);reorder() 排序;position = "dodge"/"fill" 控制分组方式;geom_text() 添加标签

  • 数值变量geom_histogram() 展示分布,binwidth 是关键参数;geom_density() 是平滑版,适合多组比较;geom_boxplot() 五数概括,异常值一目了然

  • 双变量关系geom_point() + geom_smooth() 看数值×数值关系;geom_jitter() 处理点重叠;geom_violin() 同时展示分布形状与分组

  • 多变量扩展color/size/shape 映射引入第三维度;facet_wrap() 单变量分面;facet_grid() 双变量矩阵分面;theme_*() 一行改变整体风格

课后练习

基础练习(必做)

  1. 使用 mpg 数据,用 geom_bar() 绘制各 manufacturer(品牌)的车辆数量条形图,按数量降序排列,并添加数字标签
  2. 使用 diamonds 数据,分别绘制 carat(克拉数)的直方图(至少尝试三种不同的 bins 值)和密度图,比较两种图形传达的信息有何差异
  3. 使用 mpg 数据,绘制 class(车型)× hwy(油耗)的分组箱线图,并叠加小提琴图,观察哪种车型的油耗分布最分散

进阶挑战(选做)

  1. 使用 diamonds 数据,制作一张展示 cut(切割质量)× color(颜色)的百分比堆叠条形图,使 x 轴按钻石总数从多到少排序(提示:先 count()left_join() 总数)
  2. 使用 mpg 数据,制作一张散点图展示 displ(排量)与 hwy(油耗)的关系,同时用 color 映射 drv(驱动方式),用 facet_wrap()year(年份)分面,并添加各面的线性趋势线

下讲预告

第8讲:数据可视化(下)

  • 精细控制坐标轴:scale_x_*()scale_y_*() 与坐标变换
  • 配色系统:scale_color_brewer() / scale_fill_viridis_*() 与自定义配色
  • 主题深度定制:theme() 的字体、网格线、图例位置等
  • 特殊图表:热力图(geom_tile())、折线图(geom_line())、面积图(geom_area()
  • 图形的保存与输出:ggsave() 与分辨率控制
  • 综合实战:从一份"素颜"图到发表级别的完整美化流程

提示

本讲打好了"用对图"的基础——知道什么数据用什么图形。下一讲专攻"画好图"——让图形在美观度和信息传递上都达到专业水准。

谢谢!

第7讲:数据可视化(上)


「图形是数据最诚实的镜子——它展示你的数据真正是什么,而不是你以为它是什么。」