数据框(Data Frame)是 R 语言中 最重要的数据结构,也是数据分析的绝对主力。Excel 表格中的每一行每一列,在 R 里就是数据框。90% 的数据分析工作都围绕数据框展开。
一、什么是数据框?
数据框 = 增强版的矩阵:
-
像矩阵一样有行和列
-
但不同列可以是不同类型(数值列、字符串列、逻辑列......)
-
每一列必须等长
-
本质上就是列表的列表(每列是一个向量)
姓名 年龄 数学 语文 通过 张三 20 92 85 TRUE 李四 21 88 72 TRUE 王五 19 76 95 TRUE
二、创建数据框
1. 用 data.frame() 创建
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七"),
age = c(20, 21, 19, 20, 22),
math = c(92, 88, 76, 65, 95),
chinese = c(85, 72, 95, 58, 88),
pass = c(TRUE, TRUE, TRUE, FALSE, TRUE)
)
print(students)
运行结果:
txt
name age math chinese pass
1 张三 20 92 85 TRUE
2 李四 21 88 72 TRUE
3 王五 19 76 95 TRUE
4 赵六 20 65 58 FALSE
5 孙七 22 95 88 TRUE
2. 从向量组合创建
r
names <- c("张三", "李四", "王五")
scores <- c(92, 85, 78)
df <- data.frame(names, scores)
print(df)
运行结果:
txt
names scores
1 张三 92
2 李四 85
3 王五 78
3. 字符串列的处理(重要!)
R 默认会把字符串列转成因子(Factor),可以通过参数禁止:
R 4.0 以上版本 默认已经不会自动转因子了
所以新版 R 可以不写,但:
为了兼容、为了不出错、为了教程规范 → 建议永远写上!
r
df <- data.frame(
name = c("张三", "李四", "王五"),
score = c(92, 85, 78),
stringsAsFactors = FALSE # 不自动转因子
)
三、查看数据框
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七"),
age = c(20, 21, 19, 20, 22),
math = c(92, 88, 76, 65, 95),
chinese = c(85, 72, 95, 58, 88)
)
nrow(students) # 行数 → 5
ncol(students) # 列数 → 4
dim(students) # 维度 → 5 4
names(students) # 列名
head(students, 3) # 前3行
tail(students, 2) # 后2行
str(students) # 结构
summary(students) # 统计摘要
summary() 是 R 中非常实用的函数:
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七"),
age = c(20, 21, 19, 20, 22),
math = c(92, 88, 76, 65, 95),
chinese = c(85, 72, 95, 58, 88),
stringsAsFactors = FALSE
)
summary(students)
运行结果:
txt
name age math chinese
Length:5 Min. :19.0 Min. :65.0 Min. :58.0
Class :character 1st Qu.:20.0 1st Qu.:76.0 1st Qu.:72.0
Mode :character Median :20.0 Median :88.0 Median :85.0
Mean :20.4 Mean :83.2 Mean :79.6
3rd Qu.:21.0 3rd Qu.:92.0 3rd Qu.:88.0
Max. :22.0 Max. :95.0 Max. :95.0
一行代码就能看到每列的最小值、最大值、平均值、中位数!
四、访问数据框元素
1. 用 $ 按列名访问(最常用)
r
students <- data.frame(
name = c("张三", "李四", "王五"),
math = c(92, 88, 76),
stringsAsFactors = FALSE
)
print(students$name) # 取出 name 列(返回向量)
print(students$math) # 取出 math 列
运行结果:
txt
[1] "张三" "李四" "王五"
[1] 92 88 76
2. 用 [行, 列] 访问
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六"),
math = c(92, 88, 76, 65),
chinese = c(85, 72, 95, 58),
stringsAsFactors = FALSE
)
students[1, 2] # 第1行第2列 → 92
students[1, ] # 第1行所有列
students[, 2] # 所有行第2列
students[1:3, ] # 第1-3行
students[, c("name", "math")] # 只取 name 和 math 列
3. 用列名直接取子集
r
students[, c("name", "math")]
运行结果:
txt
name math
1 张三 92
2 李四 88
3 王五 76
4 赵六 65
五、筛选数据框(条件查询)
这是数据分析中最常用的操作!
1. 单条件筛选
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七"),
math = c(92, 88, 76, 65, 95),
chinese = c(85, 72, 95, 58, 88),
stringsAsFactors = FALSE
)
# 数学成绩大于80的学生
result <- students[students$math > 80, ]
print(result)
运行结果:
txt
name math chinese
1 张三 92 85
2 李四 88 72
5 孙七 95 88
注意逗号 students[条件, ]------条件筛选行,逗号后面留空表示所有列。
2. 多条件筛选
r
# 数学>80 且 语文>80
result <- students[students$math > 80 & students$chinese > 80, ]
print(result)
运行结果:
txt
name math chinese
1 张三 92 85
5 孙七 95 88
3. 用 subset() 筛选(更易读)
r
# 筛选数学及格的学生,只显示 name 和 math 列
result <- subset(students, math >= 60, select = c(name, math))
print(result)
运行结果:
txt
name math
1 张三 92
2 李四 88
3 王五 76
4 赵六 65
5 孙七 95
六、修改数据框
1. 修改值
r
students <- data.frame(
name = c("张三", "李四", "王五"),
math = c(92, 88, 76),
stringsAsFactors = FALSE
)
# 修改某个单元格
students[2, "math"] <- 90
print(students)
# 修改整列
students$math <- students$math + 5
print(students)
运行结果:
txt
name math
1 张三 92
2 李四 90
3 王五 76
name math
1 张三 97
2 李四 95
3 王五 81
2. 添加新列
r
students <- data.frame(
name = c("张三", "李四", "王五"),
math = c(92, 88, 76),
chinese = c(85, 72, 95),
stringsAsFactors = FALSE
)
# 方法1:直接赋值
students$english <- c(78, 90, 82)
# 方法2:用 cbind 添加
students$total <- students$math + students$chinese + students$english
# 方法3:计算派生列
students$average <- round((students$math + students$chinese + students$english) / 3, 1)
print(students)
运行结果:
txt
name math chinese english total average
1 张三 92 85 78 255 85.0
2 李四 88 72 90 250 83.3
3 王五 76 95 82 253 84.3
3. 添加新行
r
students <- data.frame(
name = c("张三", "李四"),
math = c(92, 88),
stringsAsFactors = FALSE
)
# 用 rbind 添加行
new_row <- data.frame(name = "王五", math = 76, stringsAsFactors = FALSE)
students <- rbind(students, new_row)
print(students)
运行结果:
txt
name math
1 张三 92
2 李四 88
3 王五 76
4. 删除列和行
r
students <- data.frame(
name = c("张三", "李四", "王五"),
math = c(92, 88, 76),
chinese = c(85, 72, 95),
english = c(78, 90, 82),
stringsAsFactors = FALSE
)
# 删除列(赋值为 NULL)
students$english <- NULL
print(students)
# 删除行(用负索引)
students <- students[-2, ] # 删除第2行
print(students)
运行结果:
txt
name math chinese
1 张三 92 85
2 李四 88 72
3 王五 76 95
name math chinese
1 张三 92 85
3 王五 76 95
七、排序
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七"),
math = c(92, 88, 76, 65, 95),
stringsAsFactors = FALSE
)
# 按 math 降序排列
sorted <- students[order(students$math, decreasing = TRUE), ]
print(sorted)
运行结果:
txt
name math
5 孙七 95
1 张三 92
2 李四 88
3 王五 76
4 赵六 65
多列排序:
r
students <- data.frame(
name = c("张三", "李四", "王五"),
math = c(92, 88, 92),
chinese = c(85, 72, 95),
stringsAsFactors = FALSE
)
# 先按数学降序,数学相同按语文降序
sorted <- students[order(students$math, -students$chinese, decreasing = TRUE), ]
print(sorted)
运行结果:
txt
name math chinese
3 王五 92 95
1 张三 92 85
2 李四 88 72
八、分组统计
1. 用 aggregate() 分组
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六", "孙七", "周八"),
class = c("A", "A", "B", "B", "A", "B"),
math = c(92, 88, 76, 65, 95, 80),
stringsAsFactors = FALSE
)
# 按班级计算数学平均分
result <- aggregate(math ~ class, data = students, FUN = mean)
print(result)
运行结果:
txt
class math
1 A 91.66667
2 B 73.66667
2. 用 tapply 分组
r
# 按班级计算数学最高分
result <- tapply(students$math, students$class, max)
print(result)
运行结果:
txt
A B
95 80
九、处理缺失值 NA
真实数据经常有缺失值,R 用 NA 表示:
r
students <- data.frame(
name = c("张三", "李四", "王五", "赵六"),
math = c(92, NA, 76, 65),
chinese = c(85, 72, NA, 58),
stringsAsFactors = FALSE
)
print(students)
运行结果:
txt
name math chinese
1 张三 92 85
2 李四 NA 72
3 王五 76 NA
4 赵六 65 58
1. 检测缺失值
r
is.na(students$math) # 每个位置是否缺失
any(is.na(students$math)) # 整列有没有缺失
sum(is.na(students)) # 总共有多少个缺失值
2. 处理缺失值
r
# 删除有缺失值的行
na.omit(students)
# 计算时忽略缺失值
mean(students$math, na.rm = TRUE) # na.rm = TRUE 很重要!
# 用特定值填充缺失值
students$math[is.na(students$math)] <- 0
注意 :含 NA 的向量做
mean()、sum()等运算,结果也是 NA。必须加na.rm = TRUE。
十、综合实战练习(可直接复制运行)
r
# ==============================
# R 综合练习:数据框实战
# 场景:班级成绩管理与分析
# ==============================
# 1. 创建学生数据框
students <- data.frame(
id = 1:8,
name = c("张三", "李四", "王五", "赵六", "孙七", "周八", "吴九", "郑十"),
gender = c("男", "女", "男", "男", "女", "女", "男", "女"),
class = c("A", "A", "B", "B", "A", "B", "A", "B"),
math = c(92, 88, 76, 65, 95, 80, 70, 85),
chinese = c(85, 72, 95, 58, 88, 90, 62, 78),
english = c(78, 90, 82, 70, 92, 68, 55, 88),
stringsAsFactors = FALSE
)
print("=== 原始数据 ===")
print(students)
# 2. 计算总分和平均分,添加为新列
students$total <- students$math + students$chinese + students$english
students$average <- round(students$total / 3, 1)
print("=== 添加总分和平均分 ===")
print(students[, c("name", "math", "chinese", "english", "total", "average")])
# 3. 添加等级列
students$grade <- ifelse(students$average >= 90, "优秀",
ifelse(students$average >= 80, "良好",
ifelse(students$average >= 60, "及格", "不及格")))
print("=== 成绩等级 ===")
print(students[, c("name", "average", "grade")])
# 4. 按总分排名
ranked <- students[order(students$total, decreasing = TRUE), ]
ranked$rank <- 1:nrow(ranked)
print("=== 总分排名 ===")
print(ranked[, c("rank", "name", "total", "average", "grade")])
# 5. 按班级分组统计
print("=== 各班数学平均分 ===")
print(aggregate(math ~ class, data = students, FUN = mean))
print("=== 各班总分平均 ===")
print(aggregate(total ~ class, data = students, FUN = mean))
# 6. 按性别统计
print("=== 各性别平均分 ===")
print(aggregate(cbind(math, chinese, english) ~ gender, data = students, FUN = mean))
# 7. 筛选优秀学生
print("=== 优秀学生(平均分≥85)===")
top <- subset(students, average >= 85, select = c(name, class, average, grade))
print(top)
# 8. 找出有不及格科目的学生
print("=== 有不及格科目的学生 ===")
for (i in 1:nrow(students)) {
if (students$math[i] < 60 | students$chinese[i] < 60 | students$english[i] < 60) {
failed <- c()
if (students$math[i] < 60) failed <- c(failed, paste("数学", students$math[i]))
if (students$chinese[i] < 60) failed <- c(failed, paste("语文", students$chinese[i]))
if (students$english[i] < 60) failed <- c(failed, paste("英语", students$english[i]))
print(paste(students$name[i], "不及格科目:", paste(failed, collapse = ",")))
}
}
运行结果:
txt
[1] "=== 原始数据 ==="
id name gender class math chinese english
1 1 张三 男 A 92 85 78
2 2 李四 女 A 88 72 90
3 3 王五 男 B 76 95 82
4 4 赵六 男 B 65 58 70
5 5 孙七 女 A 95 88 92
6 6 周八 女 B 80 90 68
7 7 吴九 男 A 70 62 55
8 8 郑十 女 B 85 78 88
[1] "=== 添加总分和平均分 ==="
name math chinese english total average
1 张三 92 85 78 255 85.0
2 李四 88 72 90 250 83.3
3 王五 76 95 82 253 84.3
4 赵六 65 58 70 193 64.3
5 孙七 95 88 92 275 91.7
6 周八 80 90 68 238 79.3
7 吴九 70 62 55 187 62.3
8 郑十 85 78 88 251 83.7
[1] "=== 成绩等级 ==="
name average grade
1 张三 85.0 良好
2 李四 83.3 良好
3 王五 84.3 良好
4 赵六 64.3 及格
5 孙七 91.7 优秀
6 周八 79.3 及格
7 吴九 62.3 及格
8 郑十 83.7 良好
[1] "=== 总分排名 ==="
rank name total average grade
5 1 孙七 275 91.7 优秀
1 2 张三 255 85.0 良好
3 3 王五 253 84.3 良好
8 4 郑十 251 83.7 良好
2 5 李四 250 83.3 良好
6 6 周八 238 79.3 及格
4 7 赵六 193 64.3 及格
7 8 吴九 187 62.3 及格
[1] "=== 各班数学平均分 ==="
class math
1 A 86.25
2 B 76.50
[1] "=== 各班总分平均 ==="
class total
1 A 241.75
2 B 233.75
[1] "=== 各性别平均分 ==="
gender math chinese english
1 男 75.75000 75.00000 71.25000
2 女 87.00000 82.00000 84.50000
[1] "=== 优秀学生(平均分≥85)==="
name class average grade
1 张三 A 85.0 良好
5 孙七 A 91.7 优秀
[1] "=== 有不及格科目的学生 ==="
[1] "吴九 不及格科目: 英语 55"