R: R 向量 (Vector):R 编程的核心数据结构

最后更新:2026-08-26

上一课我们学了 R 的 6 种数据类型,这一课开始学 R 的核心数据结构——向量。在 Python 里写 1, 2, 3 得到的是三个独立数字,要装进列表得写 [1, 2, 3]。但 R 不一样——R 里 1, 2, 3 直接就是向量

R 的向量是整个语言的基石:数字、字符串、逻辑值都是向量。这一课我们要把向量吃透,因为它会出现在后续每一节课的代码里。

1. 你将学到



2. 一个学生成绩管理的故事

(1) 任务背景

Ivan是the class teacher,学期末要统计全班 30 个学生的成绩。他需要做这些事:

如果用 Excel,他得反复复制粘贴 + 透视表。如果用 Python,他得写列表、循环、列表推导式。但用 R——

(2) R 的解法

R
# 一行代码生成 30 个学生成绩(从 50 到 100 随机)
set.seed(42)
scores <- sample(50:100, 30, replace = TRUE)

# 一行代码完成所有统计
mean(scores)                                    # 平均分
max(scores)                                     # 最高分
sum(scores >= 60) / length(scores)              # 及格率
scores[scores >= 90]                            # 90 分以上
sort(scores, decreasing = TRUE)                  # 降序排序

10 行代码解决 5 个任务。这就是 R 向量的魅力——用最少的代码处理一列数据



3. 什么是向量?

向量(vector)是 R 里最基本的数据结构,是一组同类型元素的有序集合。

(1) 向量的本质

100%
graph LR
    A["R 向量"] --> B["原子性<br/>单个数字 = 长度1的向量"]
    A --> C["同质性<br/>所有元素同类型"]
    A --> D["有序性<br/>按位置索引 1-based"]
    A --> E["向量化<br/>运算自动逐元素"]
    
    style A fill:#fff3cd
    style B fill:#cce5ff
    style C fill:#d4edda
    style D fill:#f8d7da
    style E fill:#e1d4ff

(2) R 向量 vs Python 列表

特性 R 向量 c(1,2,3) Python 列表 [1,2,3]
元素类型 必须相同 可以不同
长度可变性 ❌ 不可变 ✅ 可变(append/remove)
算术运算 自动向量化 需要列表推导式
索引方式 x[1](1-based) x[0](0-based)
性能 C 语言底层, 通用对象,
⚠️ 注意:R 向量所有元素必须是同一种类型。如果混了,R 会自动强制转换到最"宽"的类型:

R
# 混类型:数字和字符串混合 → 全部转字符串
c(1, "a", TRUE)
# [1] "1" "a" "TRUE"
💡 提示:这是 R 跟 Python 列表最大的区别——R 向量是同质的,Python 列表是异质的。要存不同类型的数据,用列表 list()(第 9 课学)。

(3) "标量" 在 R 里不存在

R 向量有个隐藏特性:单个数字也是长度为 1 的向量

R
x <- 42
length(x)
# [1] 1

# 这就是为什么 R 的所有运算默认都是"向量化"的
c(1, 2, 3) + 10
# [1] 11 12 13


4. 4 种创建向量的方法

(1) 创建方式总览

方法 语法 适用场景
c() c(1, 2, 3) 手动列几个数(最常用)
: 1:5 连续整数序列
seq() seq(1, 10, 2) 等差数列
rep() rep(1:3, times = 2) 重复元素
paste() paste("x", 1:3) 字符串拼接

(2) 各种方法对比

R
# 1. c() —— concatenate(连接),最常用
c(10, 20, 30, 40, 50)
# [1] 10 20 30 40 50

# 2. : —— 冒号运算符,连续整数
1:5
# [1] 1 2 3 4 5

5:1
# [1] 5 4 3 2 1   ← 反向序列

# 3. seq() —— 等差数列
seq(from = 1, to = 10, by = 2)
# [1] 1 3 5 7 9

seq(from = 0, to = 1, length.out = 5)
# [1] 0.00 0.25 0.50 0.75 1.00

# 4. rep() —— 重复元素
rep(x = 1:3, times = 2)
# [1] 1 2 3 1 2 3   ← 整个向量重复 2 次

rep(x = 1:3, each = 2)
# [1] 1 1 2 2 3 3   ← 每个元素重复 2 次

# 5. paste() —— 字符串拼接
paste("第", 1:3, "名")
# [1] "第 1 名" "第 2 名" "第 3 名"

(3) 字符串向量与 paste()

R
# paste 默认 sep = " "(空格)
paste("Hello", "World")
# [1] "Hello World"

# paste0 = paste(..., sep = "") 无分隔符
paste0("Hello", "World")
# [1] "HelloWorld"

# 向量化拼接
paste(c("a", "b", "c"), 1:3, sep = "-")
# [1] "a-1" "b-2" "c-3"
💡 提示paste()paste0() 的区别是 paste0() 默认 sep = "",少打几个字,速度也快 30%。



5. 5 种访问向量元素的方式

(1) 访问方式总览

方式 语法 含义
正整数索引 x[1] 取第 1 个元素(R 是 1-based)
负整数索引 x[-1] 排除第 1 个
多个索引 x[c(1, 3)] 取第 1 和第 3 个
逻辑索引 x[x > 5] 取大于 5 的元素
命名索引 x["Bob"] 按名字取

(2) ⚠️ 重要陷阱:R 是 1-based

R
x <- c("a", "b", "c", "d", "e")

x[1]   # 第 1 个元素
# [1] "a"

x[0]   # ← 错误!空向量,不是 "a"
# numeric(0)

x[c(1, 3, 5)]   # 多个索引
# [1] "a" "c" "e"
⚠️ 注意:这是 R 最容易踩的坑——新手从 Python 过来会下意识写 x[0],得到的是空向量而不是第 1 个元素

(3) 负整数索引(排除元素)

R
x <- c("a", "b", "c", "d", "e")

x[-1]   # 排除第 1 个
# [1] "b" "c" "d" "e"

x[-c(1, 3)]   # 排除第 1 和第 3 个
# [1] "b" "d" "e"

(4) 逻辑索引(最强大)

这是 R 里最强大的索引方式:

R
x <- c(10, 20, 30, 40, 50)

# 找出大于 30 的元素
x[x > 30]
# [1] 40 50

# 找出偶数
x[x %% 2 == 0]
# [1] 10 20 30 40 50

# 多个条件(& 表示"且",| 表示"或")
x[x > 20 & x < 50]
# [1] 30 40
💡 提示:逻辑索引的本质是 x[逻辑向量]TRUE 的位置保留,FALSE 的位置过滤掉

(5) 命名索引

给向量元素起名字,再用名字访问:

R
scores <- c(Alice = 85, Bob = 92, Charlie = 78)
scores
#   Alice      Bob   Charlie
#      85       92       78

scores["Bob"]
# Bob
#  92


6. 向量运算:自动向量化

(1) 什么是"向量化"?

100%
graph LR
    A["x = 1, 2, 3"] --> C["+ 100"]
    C --> D["101, 102, 103"]
    
    E["x = 1, 2, 3"] --> F["+ y = 10, 20, 30"]
    F --> G["11, 22, 33"]
    
    style A fill:#cce5ff
    style E fill:#cce5ff
    style C fill:#fff3cd
    style F fill:#d4edda
    style D fill:#d4edda
    style G fill:#d4edda

R 的算术运算默认都是"向量化"——不需要写循环。

(2) 向量 + 标量(标量"广播")

R
x <- c(1, 2, 3, 4, 5)

x + 100   # 100 广播到每个元素
# [1] 101 102 103 104 105

x * 10
# [1] 10 20 30 40 50

(3) 向量 + 向量(对应元素运算)

R
x <- c(1, 2, 3, 4, 5)
y <- c(10, 20, 30, 40, 50)

x + y
# [1] 11 22 33 44 55

x * y
# [1]  10  40  90 160 250
💡 提示:这是 R 相比 Python 的核心优势之一。Python 想算两个列表相加得用 numpy 或列表推导式,R 一行搞定。

(4) 长度不同时会"循环"

R
c(1, 2, 3, 4) + c(10, 20)
# Warning: longer object length is not a multiple of shorter object length
# [1] 11 22 13 24
# 第二个向量循环:[10, 20, 10, 20]
⚠️ 注意长度不是整数倍时会警告。这种 bug 在 R 里很常见,写代码时确认两个向量长度一致

(5) 常用数学函数(全部向量化)

函数 作用 示例
abs() 绝对值 abs(c(-1, -2, 3))1 2 3
sqrt() 平方根 sqrt(c(1, 4, 9))1 2 3
log() 自然对数 log(c(1, exp(1)))0 1
round() 四舍五入 round(3.14159, 2)3.14
floor() ceiling() 向下/向上取整 floor(1.6)1


7. 聚合函数:把向量塌缩成一个值

函数 作用 示例
sum() 求和 sum(1:5)15
mean() 平均值 mean(1:5)3
median() 中位数 median(1:5)3
min() max() 最小最大 max(1:5)5
sd() 标准差 sd(1:5)1.581
var() 方差 var(1:5)2.5
length() 长度 length(1:5)5
prod() 连乘积 prod(1:5)120
💡 提示:这些聚合函数都接受 na.rm = TRUE 参数跳过 NA:
mean(c(1, 2, NA), na.rm = TRUE)1.5



8. 常用操作:排序、去重、查找

(1) 三大操作速查表

类别 函数 作用
排序 sort(x) 排好序的新向量
排序 order(x) 排序后的索引位置
排序 rev(x) 反转向量
去重 unique(x) 唯一值
去重 table(x) 频次统计
集合 union(a, b) 并集
集合 intersect(a, b) 交集
集合 setdiff(a, b) 差集
查找 match("a", x) 第一次出现位置
查找 "a" %in% x 是否包含元素

(2) 关键:order() vs sort()

R
x <- c(3, 1, 4, 1, 5, 9, 2, 6)

# sort() 返回排好序的向量
sort(x)
# [1] 1 1 2 3 4 5 6 9

# order() 返回排序后的**索引**
order(x)
# [1] 2 4 7 1 3 8 6 5
# 即:x 中第 2 小的排第一,第 4 小排第二...  排序后 x[order(x)] = sort(x)
💡 提示order() 在数据框排序时极其常用df[order(df$age), ] 按年龄升序排列。



9. 完整示例:学生成绩统计

下面是一个完整工作流示例,把本课所有知识点串起来。

▶ 示例:30 个学生成绩综合分析

R
# ============================================
# 学生成绩综合分析
# 功能:创建成绩向量,做 5 种统计
# ============================================

# 1. 创建 5 个学生成绩(命名向量)
scores <- c(Alice = 85, Bob = 92, Charlie = 78, David = 95, Eve = 88)
cat("原始成绩:\n")
print(scores)

# 2. 基础统计
cat("\n=== 基础统计 ===\n")
cat("总分:", sum(scores), "\n")
cat("平均分:", mean(scores), "\n")
cat("中位数:", median(scores), "\n")
cat("最高分:", max(scores), "\n")
cat("最低分:", min(scores), "\n")
cat("标准差:", round(sd(scores), 2), "\n")

# 3. 找最高分学生(命名索引)
cat("\n=== 最高分学生 ===\n")
print(scores[scores == max(scores)])

# 4. 找出 90 分以上
cat("\n=== 90 分以上学生 ===\n")
print(scores[scores >= 90])

# 5. 找出不及格
cat("\n=== 不及格学生(< 60)===\n")
print(scores[scores < 60])

# 6. 排序(降序)
cat("\n=== 成绩降序 ===\n")
print(sort(scores, decreasing = TRUE))

# 7. 标准化(z-score:所有分数减去平均再除以标准差)
z_scores <- (scores - mean(scores)) / sd(scores)
cat("\n=== Z-Score 标准化 ===\n")
print(round(z_scores, 3))

# 8. 评级(优秀/良好/及格/不及格)
ratings <- ifelse(scores >= 90, "优秀",
                  ifelse(scores >= 80, "良好",
                         ifelse(scores >= 60, "及格", "不及格")))
cat("\n=== 评级 ===\n")
print(data.frame(分数 = scores, 评级 = ratings))
▶ 试一试

预期输出(节选):

TEXT 📖 仅展示
原始成绩:
  Alice      Bob   Charlie    David      Eve
     85       92        78       95       88

=== 基础统计 ===
总分: 438
平均分: 87.6
中位数: 88
最高分: 95
最低分: 78
标准差: 6.19

=== 90 分以上学生 ===
David
   95

=== 成绩降序 ===
  David      Bob   Alice      Eve   Charlie
     95       92       85       88       78

=== Z-Score 标准化 ===
  Alice      Bob   Charlie    David      Eve
-0.420   0.711  -1.551   1.197  -0.097

(1) 操作步骤

步骤 操作 说明
1 新建 RStudio Project r-vectors File → New Project
2 新建脚本 score_analysis.R 复制上面代码
3 选中全部 → Ctrl+Enter 发送到控制台
4 观察输出 看到 6 项统计结果

❓ 常见问题

Q 为什么 R 索引从 1 开始而不是 0?
A R 是数学家设计的,遵循数学惯例(向量元素从 1 开始编号)。这是 R 跟 Python/Java/C 最大的差异之一。新手常踩坑:写 x[0] 期望拿第 1 个元素,结果拿到空向量 numeric(0)
Q 向量和矩阵什么关系?
A 矩阵是向量的"二维版"——按行列组织(一维向量 c(1,2,3,4,5,6) reshape 成 2×3 矩阵就是 matrix(1:6, nrow = 2))。

📖 小节


📝 作业

  1. 基础题:用 3 种方法创建 1~10 的整数向量:① c():seq();用 identical() 验证三者结果完全相同。截图保存控制台输出。

  2. 基础题:创建向量 x <- c(2, 4, 6, 8, 10),用逻辑索引提取出大于 5 的元素,输出筛选后的向量。把代码和输出截图保存。

  3. 基础题:用 paste() 拼接出 paste("第", 1:5, "章", sep = "") 的结果并记录;再用 paste0() 拼接 paste0("x", 1:5, "y") 的结果并记录。截图保存。

  4. 进阶题:模拟 10 个学生的成绩:① 用 sample(60:100, 10) 随机生成;② 计算平均分、中位数、最高分、最低分、标准差;③ 用 which.max() 找出最高分学生位置;④ 统计及格(≥60)人数。把每一步输出截图保存。

  5. 挑战题:写一段脚本模拟"学生分班"场景:① 构造向量 names <- c("Alice", "Bob", ...) 10 个学生名;② 构造 scores <- sample(60:100, 10) 10 个成绩;③ 用 names(scores) <- names 命名;④ 找出 90 分以上的学生姓名;⑤ 找出不及格学生姓名;⑥ 用 sort(scores) 升序排列打印。运行后截图保存控制台全部输出。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏