R 中的因素:分类变量和连续变量

⚡ 智能摘要

R 语言中的因子将分类数据存储为整数代码向量,每个代码向量对应一组级别,这就是该语言如何将有限的类别组与连续测量区分开来。

  • 🏷️ 结构体: 因子包含整数代码和级别属性,因此每个类别都会根据固定列表进行验证。
  • 🧩 创建: factor() 转换字符向量,class() 确认结果已从字符更改为因子。
  • 🔘 名义: 如果没有 levels 参数,R 会自动对类别进行排序,因此不会暗示颜色或性别之间的排名。
  • 📊 序数: 传递 ordered = TRUE 并显式指定 levels 向量,即可固定排名顺序,从最低到最高。
  • 🔢 连续: 数值列和整数列默认保持连续,如 class(mtcars$mpg) 所示。
  • ⚠️ 转化陷阱: 对因子使用 as.numeric() 会返回级别代码,因此首先通过 levels() 读取标签。
  • 🧠 保养: relevel() 设置模型基线,droplevels() 清除子集遗留的类别。

R语言中的分类变量和连续变量因素

R 中的因子是什么?

R 中的因子 因子(Factor)是一种用于对数据进行分类和存储的变量,它具有有限数量的不同值。它将数据存储为整数值的向量。在 R 语言中,因子也称为分类变量,它同时存储字符串和整数数据值作为级别。因子主要用于 R 语言的统计建模和探索性数据分析。

从内部看,因子是由两个同时移动的对象组成的:一个编码整数向量和一个名为“字符属性”的字符。 各级每个代码都是该层级向量中的一个位置,这就是为什么打印一个因子会显示单词的原因。 取消分类() 显示数字。

在数据集中,我们可以区分两种类型的变量: 明确的 和 连续.

  • 在 R 中对分类变量进行描述统计时,其值是有限的,通常基于特定的有限组。例如,R 中的分类变量可以是国家、年份、性别、职业。
  • 然而,连续变量可以取任何值,从整数到小数。例如,我们可以有收入、股票价格等等。

这种区别值得注意,因为 R 会默默地为每种数据类型选择不同的默认值。数值列会用均值和中位数进行汇总,而因子列则会用每个级别的计数进行汇总。因此,将类别存储为文本或数字会改变你得到的分析结果。更广泛的存储模式集在指南中有所介绍。 R 数据类型和运算符.

分类变量

分类变量 R 数据存储为一个因子。让我们查看下面的代码,了解如何在 R 语言中将字符变量转换为因子变量。许多建模和机器学习程序无法直接处理原始文本,因此在拟合模型之前,必须将类别编码为级别或数字。

句法

factor(x = character(), levels, labels = levels, ordered = is.ordered(x))

R 基础参考文档中还记录了上述简略形式省略的另外两个论点: 排除这会先移除水平集构建之前的值,并且 n最大,限制了转换层数的上限,从而加快了超大向量的转换速度。

参数:

  • x:R 语言中的分类数据向量。必须是字符串或整数,不能是小数。
  • 各级:x 的可能取值向量。此参数为可选参数。默认值为向量 x 的所有元素的唯一列表,并按升序排列。
  • 标签:在 R 中为 x 分类数据添加标签。例如,1 可以表示标签为男性,而 0 可以表示标签为女性。
  • 排除:用于指定在形成水平集时要删除的值的向量。被排除的值在结果中变为 NA。
  • 有序:一个逻辑标志,用于确定级别是否应按给定的顺序视为有序。
  • n最大:层数的可选上限,对于长向量很有用。

计费示例:

让我们将字符向量转换为因子,并使用 class() 确认更改。

# Create gender vector
gender_vector <- c("Male", "Female", "Female", "Male", "Male")
class(gender_vector)
# Convert gender_vector to a factor
factor_gender_vector <-factor(gender_vector)
class(factor_gender_vector)

输出:

## [1] "character"
## [1] "factor"

类从字符型切换到了因子型,但打印值没有任何变化。转换很重要。 绳子 在 R 中,在进行机器学习任务之前,将其转换为因子变量,因为此时类别才成为一个固定的、经过验证的集合。

R 中的分类变量可以分为 名义分类变量 和 序数分类变量.

名义分类变量

名义分类变量可以有多个值,但顺序无关紧要。例如,男性或女性。R 语言中的名义分类变量不包含任何顺序信息。

# Create a color vector
color_vector <- c('blue', 'red', 'green', 'white', 'black', 'yellow')
# Convert the vector to factor
factor_color <- factor(color_vector)
factor_color

输出:

## [1] blue   red    green  white  black  yellow
## Levels: black blue green red white yellow

从 factor_color 的值中,我们无法判断顺序。级别列表之所以按字母顺序排列,仅仅是因为没有提供 levels 参数,所以 R 自行对唯一值进行了排序。这种排序遵循的是当前区域设置,而不是纯 ASCII 码,这也是为什么在顺序至关重要时,需要显式指定级别的原因之一。

序数分类变量

有序分类变量确实具有自然的顺序。这种顺序来源于传递给函数的向量的顺序。 各级 参数 `ordered` 设置为 `TRUE` 会告诉 R 将该序列视为排序序列而非普通列表。设置 `ordered` 为 `FALSE` 并不会反转排序,它只会生成一个普通的无序因子。要从高到低排序,只需反转 `levels` 向量本身即可。

计费示例:

我们可以使用 summary 来计算 R 中每个因子变量的值。

# Create Ordinal categorical vector 
day_vector <- c('evening', 'morning', 'afternoon', 'midday', 'midnight', 'evening')
# Convert `day_vector` to a factor with ordered level
factor_day <- factor(day_vector, order = TRUE, levels =c('morning', 'midday', 'afternoon', 'evening', 'midnight'))
# Print the new variable
factor_day

输出:

## [1] evening   morning   afternoon midday    
midnight  evening

控制台首先打印数值,然后打印排名。下一个代码块以 Levels 行开头,该行仍然被注释掉,因此排名会保持可见,同时 summary() 调用会附加到之前的代码中。

## Levels: morning < midday < afternoon < evening < midnight
# Append the line to above code
# Count the number of occurence of each level
summary(factor_day)

输出:

##   morning    midday afternoon   evening  midnight
##         1         1         1         2         1

R 按照 levels 参数的指定顺序,将颜色级别从“早晨”到“午夜”排序。由于该因子是有序的,因此诸如 < 和 > 之类的比较运算符也适用于它,而这些运算符对上述名义颜色因子则无效。

连续变量

在 R 语言中,连续型变量是默认值,它们以数值或整数形式存储。我们可以从下面的数据集中看出这一点。mtcars 是一个内置数据集,它收集了不同类型汽车的信息。我们可以使用 `mtcars` 导入该数据集,并检查变量 `mpg`(每加仑行驶里程)的类型。它返回一个数值,表明这是一个连续型变量。

dataset <- mtcars
class(dataset$mpg)

输出

## [1] "numeric"

并非所有数值列都是真正连续的。在同一数据集中,`cyl` 列只包含 4、6 和 8,而 `am` 列只包含 0 和 1,因此它们都是恰好以数字形式存储的类别。在建模之前使用 `factor()` 函数将它们转换为连续值,可以防止 R 将 4 缸和 6 缸之间的间隙视为测量值。相反的操作,即把连续列分割成多个区间,则由 `cut()` 函数处理。

R语言中的因子水平和标签

levels 属性是您需要花费最多时间调整的部分,因为它既控制哪些内容会被打印出来,也控制模型将什么视为基线。四个基本的 R 辅助函数几乎可以涵盖所有情况。

功能 它做什么 典型用途
层级(f) 读取或替换关卡名称 将缩写重命名为易于理解的标签
nlevels(f) 返回级别数 检查类别在连接后是否没有爆炸
重新调整(f, ref) 向前移动一层 选择回归基准
droplevels(f) 移除观测值为零的层级。 子集或筛选后的清理工作

下面的代码块将这四个因素应用于之前创建的颜色和性别因素。

# Inspect the levels of an existing factor
levels(factor_color)          # the level names, in the order R stored them
nlevels(factor_color)         # how many distinct levels exist

# Rename the levels in place (the new vector must follow the same order)
levels(factor_color) <- c('Black', 'Blue', 'Green', 'Red', 'White', 'Yellow')

# Attach labels at creation time instead of renaming afterwards
gender_coded <- factor(c(1, 0, 0, 1, 1), levels = c(0, 1), labels = c('female', 'male'))

# Make 'male' the reference level that modelling functions compare against
gender_coded <- relevel(gender_coded, ref = 'male')

# Remove levels that survived a subset but no longer occur in the data
subset_color <- droplevels(factor_color[1:3])

有两个细节值得注意。`levels()` 函数会按位置重命名,因此不匹配的向量会悄悄地将类别重新标记。此外,子集会保留每个原始级别,直到调用 `droplevels()` 函数为止,这就是为什么过滤后的值会受到影响的原因。 数据框 仍然可以绘制空柱状图。 标签 参数又有所不同:它在创建时命名级别,重复的标签会将多个输入值合并到一个级别中。

如何在 R 语言中将因子转换为数值或字符型

这是 R 语言中最常见的因子错误。因为因子存储的是整数代码,所以对其调用 `as.numeric()` 函数会返回这些代码,而不是屏幕上显示的值。例如,2021 年至 2023 年的因子会返回 1、2 和 3。

# A factor whose labels happen to look like numbers
year_factor <- factor(c('2021', '2023', '2022', '2023'))

# WRONG: this returns the internal codes 1, 3, 2, 3 - not the years
as.numeric(year_factor)

# RIGHT: read the label through the levels attribute first
as.numeric(levels(year_factor))[year_factor]

# Equivalent and easier to remember, but slightly slower
as.numeric(as.character(year_factor))

# Back to plain text
as.character(year_factor)

R 基础文档推荐使用 `as.numeric(levels(f))[f]` 作为正确且稍快的写法,而 `as.numeric(as.character(f))` 则是更易读的等效写法。两者都先读取标签,然后再进行转换。

  • 性格因素as.character(f) 将标签作为纯文本返回。
  • 因式分解为整数代码: 当代码正是你想要的时,可以使用 as.integer(f) 或 unclass(f)。
  • 因素: factor(x) 或更快的 as.factor(x) 快捷方式。
  • 数值因子: factor(x) 用于离散码,cut(x, breaks) 用于需要分段的连续值。

所有这些方法都适用一项安全措施。如果 x 中的某个值未出现在 levels 向量中,factor() 函数会将该元素设置为 NA 而不是引发错误,因此多余的空格或大小写差异可能会导致行被悄悄删除。比较转换前后的唯一值,或者 对数据框进行排序 在新栏目中,问题很快就暴露出来了。

R 语言中因子型、字符型和数值型:何时使用哪种类型

尽早选择存储模式可以大大减少后续的调试工作。下表比较了文本或代码列可以采用的三种模式。

特性 因素 字符 数字
存储为 整数代码加上一个级别属性 琴弦 Doubles 或整数
固定值集 是的,按级别划分。 没有 没有
自定义显示顺序 是的,通过各个层面。 仅按字母顺序排列 仅限数字
算术 不允许 不允许 允许
模型对比 自动构建 先是被迫的 被视为一种测量

使用 因素 当值来自已知的封闭列表、显示或排名顺序很重要,或者列为模型或图表图例提供数据时,请使用此方法。 字符 适用于自由文本、标识符以及任何需要解析或连接的内容,例如名称、备注和不断更新的值的代码。 数字 只有当两个值之间的距离有意义时才适用。

下面这个方框展示了检查你实际拥有什么的最快方法。

# Ask R what each column of a data frame actually is
sapply(mtcars, class)

# Direct membership tests
is.factor(factor_day)
is.ordered(factor_day)

# unclass() exposes the integer codes hiding behind the labels
unclass(factor_color)

两个习惯可以确保选择的准确性。每次导入后都运行 `sapply(df, class)`,因为数值列中哪怕只有一个多余的字符都会将整列转换为文本。并且尽可能晚地将数据转换为因子,最好在数据清理和合并之后再进行转换。 dplyr 连接和筛选仍然比较的是普通字符串,而不是不匹配的级别集。

常见问题

如果未提供 levels 参数,factor() 函数会调用 unique() 函数并将值按升序排序。排序方式取决于当前区域设置,因此排序结果并非总是纯 ASCII 编码。如果排序结果具有实际意义,则需要显式提供 levels 参数。

`table(f)` 返回每个级别的命名计数,而 `prop.table(table(f))` 将这些计数转换为比例。两者都会显示空级别,这使得它们可用于查找筛选后消失的类别。 数据框.

factor() 函数会将每个元素与您提供的级别进行匹配,任何不匹配的值都会被标记为 NA,而不是抛出错误。转换前请检查 setdiff(unique(x), your_levels),并注意源数据中是否存在多余的空格或大小写不一致的情况。

`cut()` 函数会根据你指定的断点分割数值向量,并返回一个因子。传递标签可以生成易于理解的波段名称,如果波段需要排序,则需要设置 `ordered_result = TRUE`。如果只需要区间索引,则 `findInterval()` 函数是一个更快的选择。

自 R 4.0.0 起,`data.frame()` 和 `read.csv()` 的默认设置是 `stringsAsFactors = FALSE`,因此文本列将保持字符型。依赖自动转换的旧脚本现在必须显式地对它们所建模的列调用 `factor()` 函数。

Less 比以前更是如此。R 基础参考文档指出,相同的字符串现在共享存储空间,因此在大多数情况下差距很小。通过验证类别以及修正模型和图表中使用的级别顺序,因子仍然能够发挥作用。

大多数建模函数可以直接接受因子并自动构建虚拟对比,而许多 机器学习 软件包需要一个数值矩阵。model.matrix() 或独热编码可以弥合这种差距,并且有序因子可以保持其排名。

是的。 GitHub 副驾驶 适用于 RStudio 2023.09.0 及更高版本,并能根据打开文件中的注释和代码提供补全建议。请将级别顺序和 NA 值处理视为需要验证的建议,而非事实。

总结一下这篇文章: