在数据分析的日常工作中,我们经常需要不仅了解数据的中心趋势(如平均值),还要掌握数据的分布形态。你是否曾经想过如何快速判断一组数据中有多少比例的数值低于某个特定阈值?或者,你是否需要直观地展示数据的百分位数?这就是累积频率大显身手的地方。
在这篇文章中,我们将一起深入探讨如何使用 R 编程语言绘制累积频率图(Ogive)。我们将从基本概念入手,逐步构建代码,并通过多个实战示例,展示如何利用这种强大的可视化工具来洞察数据背后的规律。无论你是刚刚接触 R 语言,还是希望提升数据可视化技能,这篇文章都将为你提供详尽的指导和实用的技巧。
什么是累积频率?
在我们开始编写代码之前,先来明确一个核心概念。简单地讲,累积频率展示的是数据“累积”的过程。想象一下,我们有一组按顺序排列的数据。当我们把第一个类区间的频率加到第二个区间的频率上,再将这个总和加到第三个区间上,依此类推,由此得出的数值序列就是累积频率。
这种方法不仅能告诉我们某个特定区间内有多少数据,还能告诉我们低于某个上限值的数据总量。在统计学中,这是理解数据分布形状的关键步骤。
什么是累积频率图(拱形图/Ogive)?
能够显示分组数据累积频率分布的图形被称为累积频率图(Cumulative Frequency Graph),在统计学中也常被称为拱形图(Ogive)。
绘制数据是理解累积频率数据并得出结论的最有效方法。特别是在统计领域,图表至关重要,因为它们能帮助我们更好地理解数据并将其直观地呈现出来。通过累积频率图,我们可以很容易地读出中位数、四分位数以及其他百分位数。例如,如果你想知道处于前 25% 的数据分界点在哪里,看一眼这张图就能找到答案。
R 语言中的核心工具箱
为了构建专业的累积频率图,我们需要掌握 R 语言中的几个基础但强大的函数。让我们逐一了解它们的工作原理。
#### 1. seq() 方法:生成数据间隔
在绘制分组数据图表前,我们通常需要定义“箱子”或区间。seq() 方法会创建一个从下限到上限的数值列表,并根据 "by" 参数中指定的差值进行分隔。这为我们的数据分组提供了边界。
> 语法: seq(start, end, by)
> * start: 序列的起始值。
> * end: 序列的结束值。
> * by: 序列的增量(步长)。
#### 2. cut() 方法:数据分箱
R 中的 cut() 方法是数据预处理的神器。它将指定数据点向量的范围划分为若干区间,并根据数值所属的区间对其进行编码。这使得我们能够将连续的数值型数据转换为分类数据,便于统计频率。
> 语法: cut(x, breaks)
> * x: 数据点向量。
> * breaks: 断点(切分点)向量。
#### 3. table() 方法:统计频率
一旦数据被 INLINECODE20798f64 分组,我们就需要计算每个组中有多少个数据点。INLINECODEe653d4e1 方法用于创建具有指定变量名称及其对应频率的分类数据表示。它会返回一个频率表,告诉我们每个区间出现了多少次。
> 语法: table(x)
> * x: 需要转换的值向量。
#### 4. cumsum() 方法:计算累积值
这是核心步骤。我们可以使用 cumsum() 方法为指定向量生成累积频率。第 n 个区间数据点的累积频率是直到第 n 个区间的频率总和。这正是我们将“普通频率”转化为“累积频率”的关键数学运算。
> 语法: cumsum(x)
> * x: 数据点向量(通常是频率表)。
#### 5. plot() 方法:绘制图形
最后,我们可以使用 R 中的 plot() 方法创建累积频率图。该方法将断点作为 x 轴上的坐标,将其对应的累积频率作为 y 轴上的坐标作为参数。
> 语法: plot(x, y, xlab, ylab, type)
> * x-coordinates: x 坐标向量(通常是断点)。
> * y-coordinates: y 坐标向量(累积频率)。
> * xlab / ylab: 坐标轴标签。
> * type: 图形类型(如 "o" 表示同时画点和线)。
—
实战演练:从零构建累积频率图
让我们通过一个完整的例子,把上述函数串联起来。我们将创建一组模拟数据,对其进行分组、统计,并最终绘制出精美的累积频率图。
#### 第一步:创建频率表
频率表用于描述某事物在特定时间或数据区间内的频率。在这里,我们将数据点存储在变量 INLINECODE7c0b8233 中,然后使用 INLINECODEb90187ce 方法创建断点。结合使用 INLINECODE0fdb2ed2 和 INLINECODE9eab0396 方法将其转换为表格。
# 声明数据点:这里我们模拟了一组简单的观测值
data_points <- c(1, 2, 3, 5, 1, 1,
2, 4, 5, 1, 2, 3, 3)
# 声明断点:从0到6,步长为1
break_points <- seq(0, 6, by = 1)
# 转换数据:使用 cut 将数据切分,right=FALSE 表示区间为 [a, b) 形式
data_transform = cut(data_points, break_points,
right = FALSE)
# 创建频率表
data_table = table(data_transform)
# 打印频率表
print("--- 频率表 ---")
print(data_table)
输出结果:
[1] "--- 频率表 ---"
data_transform
[0,1) [1,2) [2,3) [3,4) [4,5) [5,6)
0 4 3 3 1 2
代码解读:
请注意输出中的 INLINECODEaa1352ce 区间内有 4 个数据点。这对应于原始数据中的四个 1。使用 INLINECODE24c615aa 参数非常重要,它确保了我们的区间定义是左闭右开的(例如包含 1 但不包含 2),这在统计学中更为常见,尤其是在绘制累积频率时,它能让我们更准确地定位“小于多少”的数量。
#### 第二步:计算并绘制累积频率
有了频率表,接下来的步骤就顺理成章了。我们将首先使用 cumsum() 方法制作累积频率表,然后使用该表绘制累积频率图。
为了确保图形从 x 轴的原点(或最小断点)开始,我们通常需要在累积频率序列的前面补一个 0。这对应于第一个区间之前的累积频率。
# 计算累积频率
# 注意:我们在前面拼接了一个 0,代表第一个断点之前的累积频率为 0
cumulative_freq = c(0, cumsum(data_table))
print("--- 累积频率序列 ---")
print(cumulative_freq)
# 绘制图形
# x轴使用 break_points,y轴使用 cumulative_freq
plot(break_points, cumulative_freq,
xlab = "Data Points (数据值)",
ylab = "Cumulative Frequency (累积频率)",
main = "Custom Cumulative Frequency Graph",
col = "blue",
pch = 19, # 使用实心圆点
type = "o") # type="o" 表示同时绘制点和线,并将线叠加在点上
结果分析:
运行上述代码后,你会看到一条从左下角开始向右上角延伸的折线。这条线的斜率代表了数据的密度:斜率越陡峭,说明该区间的数据越密集。
—
进阶应用:真实世界场景与模拟数据
仅仅处理简单的整数列表是不够的。在实际工作中,我们更多时候会面对连续变量,比如身高、工资或响应时间。让我们看一个更复杂的例子,使用正态分布的模拟数据。
在这个例子中,我们将探讨如何自动计算断点,以及如何美化我们的图表。
#### 示例:模拟考试成绩分布
假设我们要分析某次考试的成绩分布。我们将生成 100 个随机分数,并绘制其累积频率图。
# 设置随机种子,确保结果可复现
set.seed(123)
# 生成 100 个平均分为 70,标准差为 15 的正态分布分数
scores <- round(rnorm(100, mean = 70, sd = 15))
# 限制分数在 0 到 100 之间(模拟实际情况)
scores <- pmax(pmin(scores, 100), 0)
print(paste("分数范围:", min(scores), "-", max(scores)))
# 定义断点:从 0 到 100,每 10 分一个区间
breaks <- seq(0, 100, by = 10)
# 数据分箱
score_bins <- cut(scores, breaks = breaks, right = FALSE)
# 生成频率表
score_freq <- table(score_bins)
# 生成累积频率
score_cumsum <- c(0, cumsum(score_freq))
# 获取 x 轴坐标(断点)
x_coords <- breaks
# 绘制增强版图表
plot(x_coords, score_cumsum,
type = "o", # 点线结合
col = "darkgreen", # 绿色线条
pch = 16, # 实心三角形
lwd = 2, # 线条加粗
xlab = "Exam Score (考试分数)",
ylab = "Cumulative Count (累积人数)",
main = "Distribution of Student Scores (学生成绩分布)")
# 添加网格线以辅助阅读
grid()
# 添加一条参考线:中位数位置(即累积频率达到总人数 50% 的地方)
# 使用 abline(h = N/2) 可以在图中标出中位数的大致位置
abline(h = max(score_cumsum) / 2, col = "red", lty = 2, lwd = 2)
text(max(breaks) * 0.6, max(score_cumsum) / 2 + 2, "中位数位置", col = "red")
深入解析:
-
set.seed(123): 这是一个好习惯。它确保了你生成的随机数据在每次运行代码时都是一样的,这对于调试代码和分享结果非常重要。 - INLINECODE3adc752d: 这是一个非常有用的参数。默认情况下 INLINECODE4c67237b 如果只想画线,可能会跳过数据点。
"o"(overplot) 确保线段穿过每一个数据点,这对于阅读离散区间的累积频率非常有帮助。 - 参考线的应用: 我们在代码中添加了一条红色的虚线,表示 50% 的位置。这就是累积频率图的强大之处——你不需要通过复杂的公式计算中位数,直接在图上找到 y 轴为 50 对应的 x 值即可。
—
最佳实践与常见陷阱
在绘制累积频率图时,有几个细节是你必须注意的,否则可能会画出令人困惑的图表。
#### 1. 区间的开闭方向
在使用 INLINECODEdbd2cec2 函数时,INLINECODE75d0d73d 参数的默认值是 INLINECODE1c504eed,这意味着区间是 INLINECODE43528dd4(左开右闭)。然而,在累积频率图中,我们通常习惯于“小于 x”的频率定义,这更适合使用 INLINECODEac42e0be(左闭右开),即 INLINECODE55a67c86。
- 错误做法:忽视这个参数,导致 1 被归入 [0,1) 还是 [1,2) 产生歧义。
- 建议:在绘图前,先打印
table()的结果,检查数据分类是否符合你的预期。
#### 2. 维度不匹配
一个常见的错误是 x 轴坐标和 y 轴坐标的长度不一致。
- 如果你有 INLINECODE19d89c5c 个断点(break points),INLINECODEd153cd68 会产生
n-1个区间。 - 因此,INLINECODEe95d0707 会产生 INLINECODE35c3cc9c 个频率值。
- INLINECODE395d76d4 也会产生 INLINECODEae071479 个值。
- 关键点:为了让折线图从 x 轴的第一个断点开始画,我们需要在 y 轴数据前面补一个 0,使得 y 轴长度变为
n,与 x 轴断点数量一致。
如果不补 0,R 可能会报错,或者画出的线条会向左上方偏移,导致图表含义错误。
#### 3. 优化图形布局
如果断点非常多,x 轴可能会变得非常拥挤。
- 解决方案:可以使用
las参数旋转轴标签。
plot(..., las = 2) # 将所有标签垂直于轴旋转
axis() 函数手动控制刻度的显示,跳过部分标签。—
替代方案:使用 ecdf() 函数
除了手动计算频率表,R 还提供了一个内置的 ecdf()(Empirical Cumulative Distribution Function,经验累积分布函数)函数,它能够一步到位地计算累积概率。这在处理未分组的原始数据时非常高效。
虽然 INLINECODE8c23f7ed 返回的是一个函数对象,但我们可以直接对其绘制图形。这种方法比手动 INLINECODE69f97f1a 和 table() 更适合处理连续且没有重复值过多的数据。
# 使用之前的 scores 数据
fn <- ecdf(scores)
# 绘制经验累积分布函数图
plot(fn,
main = "ECDF of Scores using ecdf()",
xlab = "Score",
ylab = "Cumulative Probability",
col.vertical = "blue",
col.horizont = "red")
区别对比:
- 手动方法: 适合处理已分组的数据,或者你想要自定义区间宽度的情况。它给你更多的控制权。
-
ecdf()方法: 适合快速探索性数据分析(EDA),它是完全基于原始数据的,没有丢失由于分组带来的精度损失。
总结
在这篇文章中,我们全面地探讨了如何使用 R 语言绘制累积频率图。我们不仅学习了什么是累积频率以及它为何重要,还深入剖析了 R 中 INLINECODE1cbfa253, INLINECODEab0ee309, INLINECODEf165c74f, INLINECODEcc9d664f 和 plot() 这一系列组合拳的用法。
通过对比手动构建分组频率表和使用 ecdf() 函数,我们了解了不同场景下的最佳实践。累积频率图不仅仅是一根折线,它是理解数据分布、查找百分位数和进行数据比较的有力武器。
下一步建议:
尝试将这种方法应用到你自己的数据集上。你可以尝试使用 R 内置的数据集(如 INLINECODEe45e769e 或 INLINECODE4d04177d),计算其中某个连续变量(如 INLINECODEfd36ed47 或 INLINECODEf9567be4)的累积频率。当你能够自如地通过图表解读出“多少比例的数据低于某个值”时,你就已经完全掌握了这项技能。
希望这篇指南能帮助你更自信地使用 R 进行数据可视化!