第15讲:数据可视化导论——看懂图,画对图

数据挖掘与R语言

2026年10月21日

本讲导览

  • 一、前课测验(5 min)
  • 二、为什么要看图(8 min)
  • 三、人眼如何读图(8 min)
  • 四、从问题到图形(8 min)
  • 五、好图的几条底线(13 min)
  • 六、base R 动手(24 min,含课堂练习)
  • 七、控制工具(5 min)
  • 八、综合实战(14 min,含独立作图)
  • 九、总结与路线图(5 min)

重要

前三讲洗数据,第 14 讲整理文本,数据终于干净了;今天的题目是:怎样把干净的数据变成别人一眼能看懂的图? 目标不是背参数,而是建立三个判断——看什么、用什么图、怎样画得诚实。

学习目标:本讲学完你应该能够

  • 根据变量类型和分析问题,选择合适的几何图形
  • 用 base R 画出条形图、直方图、散点图、箱形图四种基本图形
  • 给图补全标题、坐标轴说明与必要的图例,并检查坐标是否误导
  • 用一句话概括图形呈现的主要信息,不把相关关系说成因果关系

提示

最后一条是数据分析师的职业底线:图能说明"两者一起变",不能说明"一个导致另一个"——因果要靠设计和检验,不靠图形。

一、前课测验

第 14 讲:文本字段的合、拆、找、输出

1.1 选择题

1. 报名表的学号挤成一列(2024-0615-02),要按横杠拆成 grade、major、seq 三列,该用哪个函数? A. unite() B. separate() C. str_detect() D. str_replace_all()

2. 哪个字段不适合用 str_replace_all(x, " ", "") 一律去掉空格? A. 姓名 B. 学号 C. 英文名 D. 专业代码

1.2 填空题

3. filter(str_detect(student_id, "E$")) 筛的是以字母 E 结尾的交换生。要改成筛出以 2024 开头的学号,把 str_detect 里的字符串写成 ______。

4. 想把结果写成一句人话:glue("全班共有 ______ 名同学。")——让变量 n 的值直接嵌进句子中间。

提示

开场一问:给你 iris 的 150 行数据,想一眼看出三种花的花瓣长度差多少,最快的下一步是再算一遍 mean,还是画一张图?——今天起,从“算”数据转到“看”数据。

二、为什么要看图

同样的统计数字,背后可能是完全不同的数据

2.1 先看一组“一样”的数据

# 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

四组数据的均值、方差、相关系数几乎完全相同。如果只看这张表,你可能会误以为四组数据具有相似的结构。请先猜:它们画出来会有什么不同?

2.2 把它们画出来

重要

同样的均值、同样的相关系数、相近的回归结果,四张图却呈现出不同结构:近似线性关系、曲线关系、受离群点影响的关系,以及由单个高杠杆点主导的关系。统计数字是对数据的压缩,压缩必然丢失信息;图形是保留结构的办法。 这就是“看图”的理由,也是整个单元的出发点。

提示

画图之前先看一眼数据的形状,是数据分析的基本习惯,不是多余的步骤。今天的全部内容,都是在学怎样把这个“看”做得准确、有效。

三、人眼如何读图

图形把数据编码成视觉元素,不同编码的精度不同

3.1 图形是“编码”

每张图都做同一件事:把数据的数值,编码成位置、长度、角度、面积、颜色等视觉通道。读图的人再把这些视觉元素解码回数值。

编码的精度不一样。心理学家 Cleveland 与 McGill 在 1980 年代做过一组经典实验,请人判断不同编码表示的数值比例,结果大致形成如下的精度排序:

3.2 视觉编码的精度排序

排序 视觉通道 典型图形 人眼判断的精度
1(最准) 共同刻度上的位置 散点图、点图 最高
2 非共同刻度上的位置 分面的散点图 较高
3 长度 条形图 较高
4 角度与斜率 饼图、折线斜率 较低
5 面积 气泡图、饼图的扇形 低
6 颜色的深浅与色相 热力图、地图上色 最低,只适合分类或粗略对比

重要

这张表给了两条实用建议:要比较数值大小,优先用位置和长度(所以条形图和散点图最可靠);颜色适合区分类别,不适合精确读数。饼图和气泡图把数值放在角度和面积上,人眼读起来最吃力。

3.3 同一组数,三种编码

提示

三张图数据完全相同。请用 10 秒比较 6 缸和 8 缸的平均 mpg。条形图和点图更便于比较数值;饼图不适合回答这种精确比较问题。注意:mpg 越高,表示每加仑汽油行驶的英里数越多,即燃油经济性越好。同一组数据,换一种编码,读图的效率就不同。

四、从问题到图形

先想清楚要回答什么问题,再决定画什么

4.1 选图两步法

  • 变量有几个
  • 变量是数值型还是分类变量。
变量个数 变量类型 选什么图 典型问题
一个 分类 条形图 哪一类最多、哪一类最少?
一个 数值 直方图、箱形图 数据集中在哪里?分布是否偏斜、是否双峰?
两个 都是数值 散点图 两者有没有关系、方向如何?
两个 数值 + 分类 箱形图、分组条形图 各组之间差多少?
按时间排列 数值 折线图 趋势如何?有没有季节规律?

五、好图的几条底线

正反对照,看看问题出在哪里

5.1 底线一:坐标要诚实

重要

三组真实均值是 26.7/19.7/15.1,6 缸对 8 缸实际只差三成(1.31 倍);可坐标从 14 开始时,可见柱高变成 5.74 对 1.10——看起来差了 5.2 倍。再看左图最粗的那根:4 缸的 26.7 已经超过上界 22,被画面沿口齐顶裁断,读者根本看不出它是最高的一组(barplot() 会照你给的 ylim 开窗,柱高仍按真实值画,超出部分直接裁掉)。比较柱高时,数值轴通常应从 0 开始。 如果确有特殊理由采用不同基线,必须明确标示,避免误导。

5.2 底线二:标注要完整

提示

好图应当回答“这是什么、在哪里、单位是什么、大小是多少”。标题说结论或内容,坐标轴说明变量和单位,必要时直接标数值。读者不需要猜。

5.3 底线三:颜色为意义服务

重要

颜色的用途有两个:区分类别(每类一色,并配图例或直接标注)和突出重点(其余灰色,重点一色)。彩虹色没有对应的含义,只会增加噪音。还要注意:约 8% 的男性存在不同程度的红绿色觉缺陷,不要只靠红绿来区分类别,可以加形状或标注。

5.4 底线四:去掉没有信息的装饰

提示

网格线、边框、阴影、立体效果,只要不帮助读数,都是噪音。美国统计学家 Edward Tufte 把图中承载数据的墨水占比称为“数据墨水比”,主张尽量提高它。实践中一个简单的标准:删掉之后读者仍能读懂的东西,就可以删。

5.5 常见的危险图表

图表 问题 替代建议
3D 柱状图 / 3D 饼图 透视让长度和面积失真 普通条形图
双纵轴图 两条线的高低可以随意调整刻度,制造“相关”假象 分两张图,或统一单位
截断的柱状图 夸大差距 从 0 开始
彩虹色表示数值大小 颜色的感知不均匀,难以对应数值 同一色系的渐变,或直接标数值

警告

这些图在财经新闻和报告中并不少见。学会识别它们,比学会画图更早用得上。 今天回去随手找一张新闻里的图,用这几条底线挑挑毛病——下节课我们会请同学来讲。

六、base R 动手:四种基本图形,每种一练

条形 · 直方 · 散点 · 箱形;先图形,再文字,再图例,再颜色

6.1 base R 的画布规矩

base R 不需要加装软件包,画图函数是 plot()、barplot()、hist()、boxplot() 等。在 Quarto 文档里,代码块运行后图形直接显示在代码块下方。

base R 把图画在一块画布上,规矩有两条:

  • ① 高级函数(从无到有)会清空画布上原来的图;
  • ② 低级函数(title()、legend()、grid() 等)只能在已有的图上叠加,所以先高级、后低级。

6.2 第一张:条形图——只有图形

▶️ 查看代码
x <- c(41, 42, 56, 57)
names(x) <- c("1班", "2班", "3班", "4班")
x
1班 2班 3班 4班 
 41  42  56  57 
▶️ 查看代码
barplot(x)

6.3 【即时练习 1】条形图:四家公司的收入

自己造四个数:四家公司(A、B、C、D)的年收入,用 c() 组成向量、用 names() 给四个名字,然后 barplot() 画出来。这一张只要图形——标题、轴说明、颜色都先不加,画完先比较一下哪家公司最高。

6.4 第二张:直方图——加上文字

▶️ 查看代码
head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
▶️ 查看代码
hist(iris$Petal.Length,
     main = "三种鸢尾花的花瓣长度分布",
     xlab = "花瓣长度(厘米)",
     ylab = "频数(株)")

重要

直方图看的是单个数值变量的分布:柱高是落在每个区间内的观测数。1–2 厘米附近有一大群(恰好 50 株),3 厘米以上还有一大片——呈双峰形态。猜猜两群分别对应哪个种?6.8 节的箱形图会给出答案。

6.5 【即时练习 2】直方图:气温分布

airquality 是 R 内置数据:1973 年 5—9 月纽约空气质量的 153 天日观测,Temp 是当日气温(华氏度)。照 6.4 节的写法,给 hist(airquality$Temp) 补上标题和两条带单位的轴说明,再用一句话说出气温集中在哪个区间。

6.6 第三张:散点图——加上图例

▶️ 查看代码
plot(iris$Petal.Width, iris$Petal.Length,
     pch = as.numeric(iris$Species),              # 用点的形状区分三个种
     main = "花瓣宽与花瓣长",
     xlab = "花瓣宽(厘米)", ylab = "花瓣长(厘米)")
legend("topleft", legend = levels(iris$Species), pch = 1:3)

提示

散点图用的是“位置”编码,是人眼最擅长的一种(3.2 节排序第 1)。图例存在的理由是“图上有分组”。这里用形状而不是颜色,黑白打印也看得清。

6.7 【即时练习 3】散点图:花萼长与花瓣宽

用 iris 画一张散点图:横轴 Sepal.Length(花萼长,厘米),纵轴 Petal.Width(花瓣宽,厘米),按 Species 用不同形状区分三个种,并照 6.6 节最后一行补上图例。画完先回答一句:点是一团,还是几条?

6.8 第四张:箱形图——加上颜色

▶️ 查看代码
boxplot(Petal.Length ~ Species, data = iris,
        col = c("steelblue", "yellow", "purple"),   # 一组一色
        main = "三种鸢尾花的花瓣长度对比",
        xlab = "种类", ylab = "花瓣长度(厘米)")

重要

读图:setosa 的箱体整体位于较低位置(中位数约 1.5 厘米),与直方图中的短花瓣群相呼应。箱形图可比较各组的中位数、离散程度和潜在异常值;但单凭箱形图,不能完整还原每组分布的形状。

6.9 【即时练习 4】箱形图:气温按月对比

用 airquality 画一张箱形图,比较五个月(Month)的 Temp 分布。照 6.8 节的做法:标题 + 两条带单位的轴说明 + 五个箱子各上一色。

七、控制工具

粗细 · 组距 · 点线 · 刻度

7.1 柱子的粗细与直方图的组距

▶️ 查看代码
barplot(x, space = 0.2, main = "space = 0.2(默认)")   # means 来自 6.10 节

▶️ 查看代码
barplot(x, space = 1.5, main = "space = 1.5:拉开距离")

▶️ 查看代码
hist(iris$Petal.Length, breaks = 20, main = "breaks = 20:组数太多,噪声盖过信号")

提示

space 控制条形图柱子之间的空当;breaks 控制直方图的组数,是直方图最重要的参数。组数太少,形状被抹平;组数太多,噪声盖过形状。breaks 是建议值,R 会取“好看”的刻度。动手改一改:把 6.5 节那张气温直方图拿过来,加一个 breaks = 6 和一个 breaks = 20,看看形状有没有被抹平或打碎。

7.2 点、线与刻度

▶️ 查看代码
par(mfrow = c(1, 2))
plot(iris$Petal.Width, iris$Petal.Length, pch = 17, cex = 1.4, col = "#2E5984",
     main = "pch = 17(实心三角),cex = 1.4", xlab = "花瓣宽(厘米)", ylab = "花瓣长(厘米)")
hist(iris$Petal.Length, xaxt = "n", main = "关掉默认刻度,用 axis() 自己画",
     xlab = "花瓣长度(厘米)")
axis(1, at = c(1, 3, 5, 7))      # side = 1 是下轴;at 给位置,labels 可换成任意文字

▶️ 查看代码
par(mfrow = c(1, 1))

提示

pch 控制点形状,cex 控制点大小,lty / lwd 控制线型与线宽。axis(side, at, labels) 可以自定义刻度位置和文字。多组数据用不同形状或线型区分,黑白打印也能分辨。

警告

散点图和折线图可以截取局部坐标范围(xlim / ylim),因为它们用的是位置编码,不是长度。但要让读者看得出刻度的范围,并避免用截取的局部去夸大变化。

八、综合实战——画一张能交差的图

选图 → 画图 → 加字 → 配色 → 验收

8.1 实战题目:画两张能交差的图

任务 A:用内置数据集 mtcars(32 辆汽车的 11 项指标),画一张箱形图,比较 4 缸、6 缸、8 缸三类汽车的油耗 mpg(每加仑行驶的英里数)。

任务 B:用同一个 mtcars,画一张散点图:横轴 wt(整车整备质量,千磅),纵轴 mpg(每加仑行驶英里数),并用点的形状区分 am(0 = 自动档、1 = 手动档),配上图例。

两张图都要按“选图 → 画图 → 加字 → 配色 → 验收”走完,并达到下面四条标准(也就是 5.1–5.4 节的底线):

  • 选图对:说得出为什么用这种图——变量个数与类型决定图型
  • 文字全:标题 + 两条坐标轴的变量名与单位,箱形图还要有分组标签
  • 分组看得见:箱形图按组配色,散点图用不同形状并配图例,一眼能指认;不用无含义的彩虹色
  • 读得出来:每张图配一句话结论,并且不把相关说成因果

提示

先自己做(约 8 分钟),再对照 8.2、8.3 的参考做法检查。动笔前先走一遍第四节的选图两步法:mpg 是数值、cyl 是分类,两个变量、一数值一分类——所以是箱形图。

8.2 任务A 参考做法:mtcars 油耗箱形图

重要

验收四件事:选图对(数值 + 分类 → 箱形图)、文字全(标题、双轴、分组标签)、有颜色(三组三色,不靠记忆区分)、读得出结论(中位数约 26、20、15 mpg:缸数越多,油耗越高,即每加仑行驶的英里数越少)。

8.3 任务B 参考做法:mtcars 车重与油耗散点图

重要

验收四件事同样适用:选图对(两个数值变量 → 散点图)、文字全(标题 + 双轴带单位 + 图例)、有区分(用形状而不是颜色分组,黑白打印也认得出)、读得出来(点整体从左上往右下走,车重与 mpg 的相关系数约 −0.87:车越重,每加仑跑的英里数越少)。

提示

任务 A 与任务 B 用的是同一份 mtcars,图形却不同——因为要回答的问题不同:A 比的是三组之间差多少(数值 + 分类 → 箱形图),B 看的是两个数值变量有没有关系(→ 散点图)。这正是第四节“选图两步法”的落点。至于选图表里的折线图,本讲不动手画,第 16 讲用 ggplot2 的 geom_line() 一次画好。

8.4 互评与找茬

互评:同桌交换两张图,照 8.1 的四条标准逐项打勾——选图对、文字全、有颜色、读得出来。哪一项打不上勾,就说清楚差在哪。

找茬:下面这张图有哪几处违反了 5.1–5.5 节的底线?请先说出来,再动手改。

▶️ 查看代码
barplot(avg, col = rainbow(3), ylim = c(14, 22))     # 故意保留的反面写法,供找茬使用

提示

答案要点:①坐标轴从 14 开始(违反底线一),顺带把最高的 4 缸柱顶裁断在画面上沿;②没有标题、没有轴说明、没有标注数值(违反底线二);③彩虹色没有对应含义(违反底线三)。改法见 5.2 节的 labels-good 代码块。

九、总结与路线图

看图的判断 + 画图的工具 = 数据可视化

9.1 本讲五件事

  • 统计数字会压缩信息,看图才能发现数据的真实结构(Anscombe 四重奏)
  • 人眼读图的精度不同:位置与长度最可靠,角度、面积次之,颜色只适合分类
  • 选图从问题出发:变量个数 + 变量类型决定图形,修饰排在最后
  • 好图的底线:坐标诚实(柱状图从 0 开始)、标注完整、颜色有意义、去掉无用装饰
  • base R 能用 plot()、barplot()、hist()、boxplot() 画出四种基本图形,并用 legend()、axis() 等函数修饰

9.2 后三讲 ggplot2 的路线

讲次 主题 核心内容 承接今天的哪部分
第16讲 图形语法入门 数据、映射(aes())、图层(geom_*())、labs() 3.1 节的编码、6.1 节的规矩
第17讲 分布、分组与配色 geom_histogram()、geom_boxplot()、颜色与图例的控制 6.4–6.9 节、5.3 节的颜色底线
第18讲 分面、主题与成品 facet_wrap()、theme()、ggsave() 导出、综合作品 6.10 节的拼图、5.1–5.4 节的底线

提示

课前准备:把今天画的四张图代码留好。下节课,同一张图我们用 ggplot2 再画一遍,对照着看,你会发现很多概念是相通的。

下课前自测

Exit ticket:三问检查是否真正学会

重要

  1. 一个数值变量想看分布,优先考虑什么图?两个数值变量想看关系呢?
  2. 为什么柱状图的数值轴通常从 0 开始,而散点图的坐标范围有时可以截取?
  3. 一张图有标题、颜色和漂亮字体,但没有单位、分组说明也看不出结论,算不算一张好图?为什么?

提示

自我检查标准:回答时不要只报出图形名称,还要说出“它适合回答什么问题”以及“读图时要注意什么”。这比记住函数参数更重要。

谢谢!

第15讲:数据可视化导论——看懂图,画对图

“The purpose of visualization is insight, not pictures.”——Ben Shneiderman 图表的目的是让人看懂数据,不是把画面填满。先准确,再好看。

朱 奇 | 锦城大学 · 财会学院