R中的因素:不仅仅是烦恼?

时间:2010-08-10 01:06:29

标签: r language-design internals r-factor

R中的一种基本数据类型是因子。根据我的经验,因素基本上是一种痛苦,我从不使用它们。我总是转换为角色。我觉得奇怪的是我错过了一些东西。

是否有一些重要的函数示例使用因子作为分组变量,其中因子数据类型变得必要?当使用因素时,是否存在具体情况?

7 个答案:

答案 0 :(得分:48)

你应该使用因素。是的,他们可能是一种痛苦,但我的理论是90%的原因是因为在read.tableread.csv中,默认情况下stringsAsFactors = TRUE参数{和大多数用户错过这个微妙)。我说它们很有用,因为像lme4这样的模型拟合包使用因子和有序因子来差异拟合模型并确定要使用的对比类型。图形包也使用它们进行分组。 ggplot和大多数模型拟合函数将字符向量强制转换为因子,因此结果是相同的。但是,您的代码中最终会出现警告:

lm(Petal.Length ~ -1 + Species, data=iris)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  

iris.alt <- iris
iris.alt$Species <- as.character(iris.alt$Species)
lm(Petal.Length ~ -1 + Species, data=iris.alt)

# Call:
# lm(formula = Petal.Length ~ -1 + Species, data = iris.alt)

# Coefficients:
#     Speciessetosa  Speciesversicolor   Speciesvirginica  
#             1.462              4.260              5.552  
  

警告讯息:model.matrix.default(mt, mf, contrasts)

     

变量Species已转换为factor

一个棘手的问题是整个drop=TRUE位。在向量中,这可以很好地去除数据中不存在的因子级别。例如:

s <- iris$Species
s[s == 'setosa', drop=TRUE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa
s[s == 'setosa', drop=FALSE]
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

然而data.frame[.data.frame()的行为不同:请参阅this email?"[.data.frame"。在drop=TRUE上使用data.frame并不像您想象的那样:

x <- subset(iris, Species == 'setosa', drop=TRUE)  # susbetting with [ behaves the same way
x$Species
#  [1] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [11] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [21] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [31] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# [41] setosa setosa setosa setosa setosa setosa setosa setosa setosa setosa
# Levels: setosa versicolor virginica

幸运的是,您可以使用droplevels()轻松删除因子,以降低单个因子或data.frame中每个因素的未使用因子水平(自R 2.12起):

x <- subset(iris, Species == 'setosa')
levels(x$Species)
# [1] "setosa"     "versicolor" "virginica" 
x <- droplevels(x)
levels(x$Species)
# [1] "setosa"

这是如何保持您从ggplot传说中选择的级别。

在内部,factor是具有属性级别字符向量的整数(请参阅attributes(iris$Species)class(attributes(iris$Species)$levels)),这是干净的。如果您必须更改级别名称(并且您使用的是字符串),那么这将是很多效率较低的操作。而且我更改了级别名称,特别是对于ggplot传说。如果您使用字符向量伪造因子,则存在您只更改一个元素并意外创建单独的新级别的风险。

答案 1 :(得分:29)

有序因素很棒,如果我碰巧喜欢橘子和讨厌苹果但不介意葡萄我不需要管理一些奇怪的索引来说明:

d <- data.frame(x = rnorm(20), f = sample(c("apples", "oranges", "grapes"), 20, replace = TRUE, prob = c(0.5, 0.25, 0.25)))
d$f <- ordered(d$f, c("apples", "grapes", "oranges"))
d[d$f >= "grapes", ]

答案 2 :(得分:18)

factor最类似于其他语言中的枚举类型。适当的用途是变量,它只能采用一组规定的值。在这些情况下,并非每个可能允许的值都存在于任何特定数据集中,而“空”级别则准确地反映了这一点。

考虑一些例子。对于在美国各地收集的一些数据,应将州记录为一个因素。在这种情况下,没有从特定州收集案件的事实是相关的。可能有来自该州的数据,但发生了(无论出于何种原因,这可能是感兴趣的原因)。如果收集家乡,那将不是一个因素。没有预先设定的可能的家乡。如果从三个城镇而不是在全国范围内收集数据,那么该镇就是一个因素:一开始就有三个选择,如果在这三个城镇中没有找到相关的案例/数据,这是相关的。

factor的其他方面,例如提供给一组字符串赋予任意排序顺序的方法,是factor s的有用次要特征,但不是它们存在的原因。

答案 3 :(得分:12)

当进行统计分析并实际探索数据时,因素非常棒。然而,在此之前,当人们正在阅读,清理,排除故障,合并并且通常操纵数据时,因素是完全痛苦的。最近,与过去几年一样,许多功能已得到改进,可以更好地处理这些因素。例如,rbind与他们很好地配合。我仍然发现在子集函数之后留下空的水平是完全令人讨厌的。

#drop a whole bunch of unused levels from a whole bunch of columns that are factors using gdata
require(gdata)
drop.levels(dataframe)

我知道重新编码因子的级别并重新标记标签是很简单的,并且还有很好的方法来重新排序级别。我的大脑根本无法记住它们,我每次使用它时都必须重新学习它。重新编码应该比它更容易。

R的字符串函数非常容易使用。因此,在操纵时,我通常更喜欢角色而不是因素。

答案 4 :(得分:6)

多么神奇的标题!

我相信许多估算函数允许您使用因子来轻松定义虚拟变量......但我不会将它们用于此。

当我有非常大的字符向量且几乎没有独特的观察时,我就使用它们。这可以减少内存消耗,特别是如果字符向量中的字符串更长时间。

PS - 我在开玩笑说这个头衔。我看到了你的推文。 ; - )

答案 5 :(得分:1)

因素是一个优秀的&#34;独特的案例&#34;徽章引擎。我重复了这么多次,尽管偶尔会有一些皱纹,但它们非常强大。

library(dplyr)
d <- tibble(x = sample(letters[1:10], 20, replace = TRUE))

## normalize this table into an indexed value across two tables
id <- tibble(x_u = sort(unique(d$x))) %>% mutate(x_i = row_number())
di <- tibble(x_i = as.integer(factor(d$x)))


## reconstruct d$x when needed
d2 <- inner_join(di, id) %>% transmute(x = x_u)
identical(d, d2)
## [1] TRUE

如果有更好的方法来完成这项任务,我很乐意看到它,我不会看到factor所讨论的这种能力。

答案 6 :(得分:-2)

tapply (以及 汇总 )依赖于因素。这些功能的信息与工作量比非常高。

例如,在一行代码(下面对 tapply 的调用)中,您可以通过剪切和颜色获得钻石的平均价格:

> data(diamonds, package="ggplot2")

> head(dm)

   Carat     Cut    Clarity Price Color
1  0.23     Ideal     SI2   326     E
2  0.21   Premium     SI1   326     E
3  0.23      Good     VS1   327     E


> tx = with(diamonds, tapply(X=Price, INDEX=list(Cut=Cut, Color=Color), FUN=mean))

> a = sort(1:diamonds(tx)[2], decreasing=T)  # reverse columns for readability

> tx[,a]

         Color
Cut         J    I    H    G    F    E    D
Fair      4976 4685 5136 4239 3827 3682 4291
Good      4574 5079 4276 4123 3496 3424 3405
Very Good 5104 5256 4535 3873 3779 3215 3470
Premium   6295 5946 5217 4501 4325 3539 3631
Ideal     4918 4452 3889 3721 3375 2598 2629