在R语言中,factor 叫做 因子类型。
它主要用来表示 分类变量。
比如:
这些变量不是连续数值,而是类别,所以适合用 factor。
先创建一个性别变量。
gender <- c("男", "女", "女", "男", "男", "女")
gender
## [1] "男" "女" "女" "男" "男" "女"
查看类型:
class(gender)
## [1] "character"
此时结果是:
character
说明它现在只是字符型。
使用 factor() 函数。
gender_factor <- factor(gender)
gender_factor
## [1] 男 女 女 男 男 女
## Levels: 男 女
查看类型:
class(gender_factor)
## [1] "factor"
结果会是:
factor
查看因子的水平:
levels(gender_factor)
## [1] "男" "女"
这里的 levels 就是因子的类别。
factor(x, levels = NULL, labels = NULL, ordered = FALSE)
常用参数:
| 参数 | 含义 |
|---|---|
x |
要转换的变量 |
levels |
指定类别顺序 |
labels |
给类别重新命名 |
ordered |
是否为有序因子 |
levels 表示因子的类别,也叫水平。
例如:
gender_factor <- factor(gender)
levels(gender_factor)
## [1] "男" "女"
R会自动按一定规则生成水平,比如:
女 男
但是很多时候,我们希望自己指定顺序。
例如我们希望顺序是:
男,女
可以这样写:
gender_factor2 <- factor(gender, levels = c("男", "女"))
gender_factor2
## [1] 男 女 女 男 男 女
## Levels: 男 女
levels(gender_factor2)
## [1] "男" "女"
这时因子的顺序就是我们指定的:
男 女
因为在绘图、排序、建模时,R会按照因子水平顺序显示。
比如我们创建一个数据框:
df <- data.frame(
group = c("低", "中", "高", "低", "中", "高"),
score = c(60, 75, 90, 65, 80, 95)
)
df
## group score
## 1 低 60
## 2 中 75
## 3 高 90
## 4 低 65
## 5 中 80
## 6 高 95
查看结构:
str(df)
## 'data.frame': 6 obs. of 2 variables:
## $ group: chr "低" "中" "高" "低" ...
## $ score: num 60 75 90 65 80 95
此时 group 可能是字符型。
df$group_factor <- factor(df$group)
df
## group score group_factor
## 1 低 60 低
## 2 中 75 中
## 3 高 90 高
## 4 低 65 低
## 5 中 80 中
## 6 高 95 高
levels(df$group_factor)
## [1] "低" "高" "中"
你可能会发现顺序不是你想要的。
例如R可能按字符顺序排列:
低 高 中
但是在逻辑上,我们希望顺序是:
低 中 高
df$group_factor2 <- factor(df$group, levels = c("低", "中", "高"))
df
## group score group_factor group_factor2
## 1 低 60 低 低
## 2 中 75 中 中
## 3 高 90 高 高
## 4 低 65 低 低
## 5 中 80 中 中
## 6 高 95 高 高
levels(df$group_factor2)
## [1] "低" "中" "高"
这样顺序就是:
低 中 高
如果类别本身有大小顺序,比如:
低 < 中 < 高
就可以设置为有序因子。
df$group_ordered <- factor(
df$group,
levels = c("低", "中", "高"),
ordered = TRUE
)
df
## group score group_factor group_factor2 group_ordered
## 1 低 60 低 低 低
## 2 中 75 中 中 中
## 3 高 90 高 高 高
## 4 低 65 低 低 低
## 5 中 80 中 中 中
## 6 高 95 高 高 高
查看类型:
class(df$group_ordered)
## [1] "ordered" "factor"
结果可能是:
ordered factor
查看是否有顺序:
df$group_ordered
## [1] 低 中 高 低 中 高
## Levels: 低 < 中 < 高
你会看到类似:
[1] 低 中 高 低 中 高
Levels: 低 < 中 < 高
因为 group_ordered 是有序因子,所以可以比较。
df$group_ordered > "低"
## [1] FALSE TRUE TRUE FALSE TRUE TRUE
结果中,中 和 高 会是 TRUE,低
是 FALSE。
有时候原始数据是数字编码:
1 = 男
2 = 女
我们可以用 labels 改成文字。
sex_code <- c(1, 2, 2, 1, 1, 2)
sex_factor <- factor(
sex_code,
levels = c(1, 2),
labels = c("男", "女")
)
sex_factor
## [1] 男 女 女 男 男 女
## Levels: 男 女
查看水平:
levels(sex_factor)
## [1] "男" "女"
结果:
男 女
satisfaction_code <- c(1, 2, 3, 2, 1, 3, 3)
satisfaction <- factor(
satisfaction_code,
levels = c(1, 2, 3),
labels = c("不满意", "一般", "满意"),
ordered = TRUE
)
satisfaction
## [1] 不满意 一般 满意 一般 不满意 满意 满意
## Levels: 不满意 < 一般 < 满意
查看结果:
levels(satisfaction)
## [1] "不满意" "一般" "满意"
class(satisfaction)
## [1] "ordered" "factor"
结果中会显示:
不满意 < 一般 < 满意
对于因子变量,经常需要统计各类别数量。
table(gender_factor2)
## gender_factor2
## 男 女
## 3 3
也可以对数据框里的因子变量统计:
table(df$group_factor2)
##
## 低 中 高
## 2 2 2
比如我们想计算不同等级的平均分。
aggregate(score ~ group_factor2, data = df, mean)
## group_factor2 score
## 1 低 62.5
## 2 中 77.5
## 3 高 92.5
结果类似:
group_factor2 score
1 低 62.5
2 中 77.5
3 高 92.5
因子的顺序会影响图形横轴顺序。
先加载绘图包:
library(ggplot2)
如果没有安装,可以先运行:
install.packages("ggplot2")
ggplot(df, aes(x = group_factor, y = score)) +
geom_col()
这里横轴顺序可能不是:
低 中 高
ggplot(df, aes(x = group_factor2, y = score)) +
geom_col()
这时横轴顺序就是:
低 中 高
所以:
如果图形顺序不对,通常要检查 factor 的 levels。
ggplot(df, aes(x = group_factor2, y = score)) +
geom_boxplot()
因为 group_factor2
是因子,所以R会把它当作分类变量处理。
假设现在有一个变量:
level <- factor(c("A", "B", "C", "A", "B"))
level
## [1] A B C A B
## Levels: A B C
查看水平:
levels(level)
## [1] "A" "B" "C"
可以直接修改:
levels(level) <- c("低级", "中级", "高级")
level
## [1] 低级 中级 高级 低级 中级
## Levels: 低级 中级 高级
注意:
修改的时候,新的名称要和原来的水平一一对应。
如果直接给因子赋一个不存在的新类别,可能会出问题。
f <- factor(c("A", "B", "A"))
f
## [1] A B A
## Levels: A B
levels(f)
## [1] "A" "B"
如果直接这样写:
f[1] <- "C"
可能会出现:
invalid factor level, NA generated
因为原来的水平只有:
A, B
没有 C。
正确做法是先增加水平:
levels(f) <- c(levels(f), "C")
f[1] <- "C"
f
## [1] C B A
## Levels: A B C
levels(f)
## [1] "A" "B" "C"
有时候我们不想让变量保持 factor 类型,可以转成字符型。
f_char <- as.character(f)
f_char
## [1] "C" "B" "A"
class(f_char)
## [1] "character"
这是非常重要的考试易错点。
创建一个因子:
num_factor <- factor(c("10", "20", "30"))
num_factor
## [1] 10 20 30
## Levels: 10 20 30
如果直接转数字:
as.numeric(num_factor)
## [1] 1 2 3
你会发现结果不是:
10 20 30
而是类似:
1 2 3
为什么?
因为因子底层存储的是水平编号。
应该先转字符,再转数字:
as.numeric(as.character(num_factor))
## [1] 10 20 30
结果才是:
10 20 30
记住:
as.numeric(factor变量)
得到的是因子编号,不一定是原始数字。
正确写法:
as.numeric(as.character(factor变量))
创建一个因子:
class_factor <- factor(
c("一班", "一班", "二班"),
levels = c("一班", "二班", "三班")
)
class_factor
## [1] 一班 一班 二班
## Levels: 一班 二班 三班
levels(class_factor)
## [1] "一班" "二班" "三班"
虽然数据中没有“三班”,但 levels 里仍然有“三班”。
如果想删除没有出现的水平:
class_factor2 <- droplevels(class_factor)
class_factor2
## [1] 一班 一班 二班
## Levels: 一班 二班
levels(class_factor2)
## [1] "一班" "二班"
students <- data.frame(
class = factor(
c("一班", "一班", "二班"),
levels = c("一班", "二班", "三班")
),
score = c(80, 85, 90)
)
students
## class score
## 1 一班 80
## 2 一班 85
## 3 二班 90
levels(students$class)
## [1] "一班" "二班" "三班"
筛选出一班:
students_one <- students[students$class == "一班", ]
students_one
## class score
## 1 一班 80
## 2 一班 85
levels(students_one$class)
## [1] "一班" "二班" "三班"
你会发现 levels 里可能还保留:
一班 二班 三班
删除未使用水平:
students_one$class <- droplevels(students_one$class)
students_one
## class score
## 1 一班 80
## 2 一班 85
levels(students_one$class)
## [1] "一班"
普通因子:
normal_factor <- factor(c("低", "中", "高"), levels = c("低", "中", "高"))
normal_factor
## [1] 低 中 高
## Levels: 低 中 高
有序因子:
ordered_factor <- factor(
c("低", "中", "高"),
levels = c("低", "中", "高"),
ordered = TRUE
)
ordered_factor
## [1] 低 中 高
## Levels: 低 < 中 < 高
普通因子的 levels 显示为:
Levels: 低 中 高
有序因子的 levels 显示为:
Levels: 低 < 中 < 高
is.factor(gender_factor2)
## [1] TRUE
is.factor(gender)
## [1] FALSE
gender <- c("男", "女", "女", "男")
gender_f <- factor(gender)
gender_f
## [1] 男 女 女 男
## Levels: 男 女
grade <- c("中", "高", "低", "中", "高")
grade_f <- factor(grade, levels = c("低", "中", "高"))
grade_f
## [1] 中 高 低 中 高
## Levels: 低 中 高
grade_ordered <- factor(
grade,
levels = c("低", "中", "高"),
ordered = TRUE
)
grade_ordered
## [1] 中 高 低 中 高
## Levels: 低 < 中 < 高
code <- c(1, 2, 1, 3, 2)
code_f <- factor(
code,
levels = c(1, 2, 3),
labels = c("低", "中", "高")
)
code_f
## [1] 低 中 低 高 中
## Levels: 低 中 高
table(code_f)
## code_f
## 低 中 高
## 2 2 1
score_df <- data.frame(
grade = factor(c("低", "中", "高", "低", "中", "高"),
levels = c("低", "中", "高")),
score = c(60, 75, 90, 65, 80, 95)
)
aggregate(score ~ grade, data = score_df, mean)
## grade score
## 1 低 62.5
## 2 中 77.5
## 3 高 92.5
现在有一个学生数据:
student <- data.frame(
id = 1:8,
gender = c(1, 2, 1, 2, 1, 2, 1, 2),
level = c("中", "高", "低", "中", "高", "低", "中", "高"),
score = c(78, 90, 60, 82, 95, 65, 80, 88)
)
student
## id gender level score
## 1 1 1 中 78
## 2 2 2 高 90
## 3 3 1 低 60
## 4 4 2 中 82
## 5 5 1 高 95
## 6 6 2 低 65
## 7 7 1 中 80
## 8 8 2 高 88
要求:
gender 转换成因子,1表示男,2表示女;level 转换成有序因子,顺序是:低 < 中 <
高;student$gender_f <- factor(
student$gender,
levels = c(1, 2),
labels = c("男", "女")
)
student
## id gender level score gender_f
## 1 1 1 中 78 男
## 2 2 2 高 90 女
## 3 3 1 低 60 男
## 4 4 2 中 82 女
## 5 5 1 高 95 男
## 6 6 2 低 65 女
## 7 7 1 中 80 男
## 8 8 2 高 88 女
student$level_f <- factor(
student$level,
levels = c("低", "中", "高"),
ordered = TRUE
)
student
## id gender level score gender_f level_f
## 1 1 1 中 78 男 中
## 2 2 2 高 90 女 高
## 3 3 1 低 60 男 低
## 4 4 2 中 82 女 中
## 5 5 1 高 95 男 高
## 6 6 2 低 65 女 低
## 7 7 1 中 80 男 中
## 8 8 2 高 88 女 高
table(student$gender_f)
##
## 男 女
## 4 4
level_mean <- aggregate(score ~ level_f, data = student, mean)
level_mean
## level_f score
## 1 低 62.5
## 2 中 80.0
## 3 高 91.0
ggplot(level_mean, aes(x = level_f, y = score)) +
geom_col(fill = "skyblue") +
labs(
title = "不同水平的平均分",
x = "水平",
y = "平均分"
)
# 字符转因子
f <- factor(c("男", "女", "男"))
# 指定因子顺序
grade <- factor(
c("中", "高", "低"),
levels = c("低", "中", "高")
)
# 有序因子
grade_ordered <- factor(
c("中", "高", "低"),
levels = c("低", "中", "高"),
ordered = TRUE
)
# 数字编码转标签
sex <- factor(
c(1, 2, 1),
levels = c(1, 2),
labels = c("男", "女")
)
# 查看因子水平
levels(sex)
## [1] "男" "女"
# 统计频数
table(sex)
## sex
## 男 女
## 2 1
# 删除未使用水平
droplevels(sex)
## [1] 男 女 男
## Levels: 男 女
# 因子转字符
as.character(sex)
## [1] "男" "女" "男"
# 因子正确转数字
num_f <- factor(c("10", "20", "30"))
as.numeric(as.character(num_f))
## [1] 10 20 30
因子 factor 的核心作用是:
把变量当作“分类变量”处理,并且可以通过
levels控制类别顺序,通过labels修改类别名称,通过ordered = TRUE设置有序类别。
考试重点记住:
factor(x, levels = ..., labels = ..., ordered = TRUE)