如何使用 R 语言和 ggplot2 绘制专业的碎石图

在数据科学的探索性分析(EDA)阶段,当我们面对包含大量变量的数据集时,经常会感到无从下手。变量太多不仅会增加计算负担,还会导致“维度灾难”,使得数据可视化变得异常困难。这时,主成分分析 就成了我们的得力助手,它能帮助我们简化数据结构,找出数据中最核心的变化趋势。

但是,在运行 PCA 之前或之后,你是否有这样的疑问:“我究竟应该保留多少个主成分才算合适?”如果保留太少,可能会丢失关键信息;如果保留太多,又失去了降维的意义。为了解决这个问题,今天我们将一起深入探讨一种经典的可视化工具——碎石图

在这篇文章中,我们将不仅仅学会如何画图,还会深入理解其背后的统计原理。我们将使用 R 语言中最强大的可视化包 ggplot2,结合经典的鸢尾花数据集,带你从零开始,手把手绘制出专业、美观的碎石图。无论你是刚入门 R 语言的新手,还是希望提升可视化质量的资深开发者,我相信你都会在接下来的内容中找到实用的技巧。

为什么碎石图如此重要?

在开始敲代码之前,让我们先达成一个共识:理解数据是分析的第一步。PCA 的核心思想是将原始的相关变量转化为一系列不相关的主成分,这些主成分按照方差解释量的大小进行排序。

  • 第一主成分(PC1):捕获了数据中最大的方差。
  • 第二主成分(PC2):捕获了剩余方差中最大的部分,以此类推。

碎石图通过以主成分序号为横坐标,以方差解释量为纵坐标,展示了每个主成分对数据信息的贡献程度。通过观察这条曲线(通常像陡峭的悬崖后拖着一条尾巴,因此得名“Scree Plot”),我们可以利用“肘部法则”来决定保留多少个主成分——即找到曲线由陡峭变平缓的那个转折点。

步骤 1:数据预处理与清洗

PCA 对数据类型很敏感,它仅适用于数值型数据。如果你的数据集中包含分类变量(如“男/女”、“A/B/C”),直接运行 PCA 会报错或产生无意义的结果。

让我们以 R 语言内置的 INLINECODEe11a9318(鸢尾花)数据集为例。这个数据集包含 5 个列,其中 INLINECODE1efad2a5(物种)是分类变量,其余 4 个列是花萼和花瓣的长宽数值。

加载必要的库

首先,我们需要加载 INLINECODE296f825b 库。如果你还没安装,请先运行 INLINECODE5d86ab5b。

# 加载 ggplot2 可视化库
library(ggplot2)

# 为了方便数据处理,我们也加载 dplyr 库(可选,但推荐)
library(dplyr) 

清理非数值列

我们需要剔除 INLINECODE3ba81e03 列。这里我们使用 base R 中的 INLINECODE4382b30d 函数,或者使用 INLINECODEee344f95 的 INLINECODE633f5d2f 函数。为了保持代码的兼容性,我们采用 subset() 方法。

# 查看原始数据结构
str(iris)

# 从原始数据集中移除 Species 列
# subset 是筛选数据最直观的方式之一
num_iris <- subset(iris, select = -c(Species))

# 查看清洗后的数据前几行
head(num_iris)

输出示例:

  Sepal.Length Sepal.Width Petal.Length Petal.Width
1          5.1         3.5          1.4         0.2
2          4.9         3.0          1.4         0.2
3          4.7         3.2          1.3         0.2
4          4.6         3.1          1.5         0.2
5          5.0         3.6          1.4         0.2
6          5.4         3.9          1.7         0.4

现在,num_iris 就是一个纯数值矩阵了,非常适合进行 PCA 分析。

步骤 2:计算主成分分析 (PCA)

有了干净的数据,接下来就是计算 PCA。在 R 语言中,prcomp() 函数是进行主成分分析的标准函数,它基于奇异值分解(SVD)算法,数值稳定性非常好。

代码实现

我们需要注意 INLINECODE3266f176 参数(注意这里有个点,通常简写为 INLINECODE9e9aab48)。如果你的变量单位不同(比如一个变量是几万元,另一个是几厘米),为了消除量纲影响,务必设置 scale = TRUE

# 使用 prcomp 函数计算主成分
# scale. = TRUE 表示对数据进行标准化(减去均值,除以标准差)
pca_result <- prcomp(num_iris, scale. = TRUE)

# 打印 PCA 结果摘要
# 这里包含了标准差、方差贡献比例和累计方差贡献比例
summary(pca_result)

输出解释:

summary() 的输出非常重要,它告诉我们每个主成分解释了多少百分比的方差。例如,PC1 可能解释了 73% 的方差,PC2 解释了 22% 等等。我们要绘制的碎石图,其实就是将这些数字可视化。

步骤 3:计算方差贡献值

虽然 summary() 能看到结果,但为了绘图,我们需要提取出具体的数值。

原理解析

在 INLINECODEf7266a12 返回的对象中,INLINECODEcaf79781 包含了每个主成分的标准差。方差(Variance)就是标准差的平方。方差贡献比例 等于该主成分的方差除以总方差。

公式如下:

$$ \text{Variance Explained} = \frac{ ext{PC}_i \text{ Variance}}{\text{Total Variance}} $$

代码提取

# 提取标准差
std_dev <- pca_result$sdev

# 计算方差(标准差的平方)
variance <- std_dev^2

# 计算每个主成分解释的方差比例
# 这就是我们要在 Y 轴上展示的数据
variance_ratio <- variance / sum(variance)

# 打印结果看看
print(variance_ratio)

输出结果示例:

[1] 0.729624454 0.228507618 0.036689219 0.005178709

这里我们看到,第一个数字(PC1)解释了约 73% 的数据差异,第二个(PC2)解释了约 23%。

步骤 4:使用 ggplot2 绘制碎石图

现在到了最激动人心的部分!我们将使用 ggplot2 将上述计算结果绘制成图表。为了让你掌握更多技能,我将展示三种不同风格的绘图方式:基础折线图、柱状图以及更高级的数据框映射法。

方法一:使用 qplot 快速绘制折线图

INLINECODE11a45065 是 INLINECODE40f92b8c 的快速绘图函数,语法类似于 base R 的 plot 函数,非常适合快速原型设计。

在这个例子中,我们绘制 PC 序号(1到4)与方差比例的关系,并添加折线和点。

# 确保已加载 ggplot2
library(ggplot2)

# 使用 qplot 快速绘图
# c(1:4) 生成主成分的序号,即 X 轴
qplot(c(1:4), variance_ratio, 
      geom = c("line", "point"), # 同时绘制线和点
      size = I(4),                # 设置点的大小
      xlab = "Principal Component", 
      ylab = "Variance Explained", 
      main = "Scree Plot - Basic Line") +
  ylim(0, 1) +                    # 设置 Y 轴范围
  theme_minimal()                 # 使用简洁主题

实用见解:通过观察这幅图,你会发现在 PC2 之后,线条迅速变平。这意味着 PC3 和 PC4 对整体方差的贡献微乎其微。在实际项目中,我们可能会选择只保留前两个主成分,从而将数据从 4 维压缩到 2 维。

方法二:绘制柱状图形式的碎石图

有时候,柱状图能更直观地展示每个主成分方差贡献的“分量”。我们可以使用 geom_col() 来实现。

# 绘制柱状图
qplot(c(1:4), variance_ratio) + 
  geom_col(fill = "steelblue", color = "black") + # 填充颜色和边框
  xlab("Principal Component") + 
  ylab("Variance Explained - Proportion") +
  ggtitle("Scree Plot - Bar Chart") +
  ylim(0, 1) +
  theme_bw() + # 黑白主题,显得更学术
  geom_text(aes(label = round(variance_ratio, 2)), vjust = -0.5) # 添加数值标签

这里我添加了一个小技巧:geom_text()。它能直接在柱子上方显示具体的数值,这在制作报告图表时非常有用,观众不需要去对着 Y 轴猜数值。

方法三:专业级绘制(数据框映射法)

在实际工作中,我们通常不会直接使用向量绘图,而是先创建一个结构化的数据框。这样做的好处是代码更易读,且更容易扩展(例如添加主成分名称)。

# 创建一个专门用于绘图的数据框
# PC 列代表主成分编号,Variance 列代表方差比例
plot_data <- data.frame(
  PC = paste0("PC", 1:length(variance_ratio)),
  Variance = variance_ratio
)

# 使用 ggplot() 函数进行标准绘图
p <- ggplot(plot_data, aes(x = PC, y = Variance, group = 1)) +
  # 绘制折线
  geom_line(color = "#00AFBB", size = 1.5) + 
  # 绘制点
  geom_point(color = "#FC4E07", size = 4, shape = 21, fill = "white") + 
  # 添加主题和标签
  theme_classic() +
  labs(
    title = "PCA Scree Plot with ggplot2",
    subtitle = "Visualizing Variance Explained by Each Component",
    x = "Principal Components",
    y = "Proportion of Variance Explained"
  ) +
  # 添加一条参考线,帮助识别肘部
  geom_hline(yintercept = 0.10, linetype = "dashed", color = "gray")

# 展示图表
print(p)

在这个进阶示例中,我们使用了 ggplot() 的标准图层语法,并添加了一条虚线作为参考线(比如 10% 的阈值),这能帮助我们更清晰地判断哪些主成分是不重要的。

深入探讨与最佳实践

如何解读碎石图?

绘制出图表只是第一步,解读它才是关键。

  • 寻找肘部:观察曲线,找到它由陡峭变为平缓的转折点。在鸢尾花数据集中,PC2 到 PC3 之间就是一个明显的转折。
  • 累计方差贡献:除了单个方差,我们通常还需要计算累计方差。如果你发现前两个主成分加起来解释了 95% 的方差,那么这两个成分就足以代表原始数据了。

常见错误与解决方案

  • 忘记标准化数据:如果你在 INLINECODE8c0a1da4 中没有设置 INLINECODE2ec607b0,且你的变量单位不同,碎石图可能会误导你。方差最大的变量可能会主导 PC1,仅仅是因为它的数值很大(比如工资 vs 年龄)。最佳实践:对于包含不同量纲变量的数据集,始终开启标准化。
  • X 轴标签问题:很多新手直接用 1:4 作为 X 轴,导致图表上显示的是数字 1, 2, 3, 4 而不是 "PC1", "PC2"。通过上述“方法三”中的数据框映射,你可以轻松解决这个问题,使图表更专业。

性能优化建议

对于像鸢尾花这样的小数据集,计算速度可以忽略不计。但当你处理数百万行的大数据时,PCA 可能会变慢。建议在调用 prcomp 之前,先移除方差极小(即几乎不变)的列,因为这些列对主成分没有贡献,只会增加计算开销。

总结与后续步骤

在本文中,我们一起学习了如何使用 R 语言和 ggplot2 库来绘制碎石图。我们不仅完成了从数据清洗、PCA 计算、方差提取到最终绘制的全过程,还深入探讨了如何通过可视化结果来决定保留多少个主成分。

核心要点回顾:

  • PCA 适合数值数据,记得预处理(删除非数值列,标准化)。
  • 碎石图 帮助我们直观地看到每个主成分的重要性。
  • ggplot2 提供了灵活的绘图方式,从 qplot 到完整的数据框映射,能满足不同场景的需求。

下一步建议

既然你已经掌握了碎石图的绘制方法,我建议你接下来尝试:

  • 绘制双标图:在碎石图的基础上,尝试绘制 PCA 的 Biplot,它能在同一张图上展示样本点和变量向量。
  • 应用实战:找一个高维数据集(例如手写数字识别数据集 MNIST 的一部分),运行 PCA 并绘制碎石图,看看能减少多少维度而不失真。

希望这篇文章对你有所帮助!如果你在练习中遇到任何问题,欢迎随时查阅 R 语言的相关文档或在社区中交流。祝你的数据科学之旅越走越远!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/49479.html
点赞
0.00 平均评分 (0% 分数) - 0