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

R中的因素:不仅仅是烦恼?,r,language-design,internals,r-factor,R,Language Design,Internals,R Factor,R中的基本数据类型之一是因子。根据我的经验,这些因素基本上是一种痛苦,我从不使用它们。我总是转换成字符。我奇怪地觉得我错过了什么 在需要因子数据类型的情况下,是否有一些使用因子作为分组变量的函数的重要示例?有没有具体的情况下我应该使用因子?多么尖刻的标题 我相信许多估计函数允许您使用因子轻松定义虚拟变量。。。但我不使用它们 我使用它们时,我有非常大的字符向量,很少有独特的观察。这可以减少内存消耗,特别是当字符向量中的字符串较长时 PS-我是在开标题玩笑。我看到了你的推特 你应该使用因子。是的,它

R中的基本数据类型之一是因子。根据我的经验,这些因素基本上是一种痛苦,我从不使用它们。我总是转换成字符。我奇怪地觉得我错过了什么

在需要因子数据类型的情况下,是否有一些使用因子作为分组变量的函数的重要示例?有没有具体的情况下我应该使用因子?

多么尖刻的标题

我相信许多估计函数允许您使用因子轻松定义虚拟变量。。。但我不使用它们

我使用它们时,我有非常大的字符向量,很少有独特的观察。这可以减少内存消耗,特别是当字符向量中的字符串较长时


PS-我是在开标题玩笑。我看到了你的推特

你应该使用因子。是的,它们可能是一种痛苦,但我的理论是,90%的痛苦是因为在
read.table
read.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  
但是,对于
data.frame
s,
[.data.frame()
的行为是不同的:请参见或
?“[.data.frame”
。在
data.frame
上使用
drop=TRUE
并不像您想象的那样工作:

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
这是如何保持您从进入
ggplot
图例中选择的级别


在内部,
因子
s是带有属性级字符向量的整数(请参见
属性(iris$Species)
类(属性(iris$Species)$levels)
),这是干净的,这将是一个效率要低得多的操作。我经常更改级别名称,尤其是对于
ggplot
图例。如果您使用字符向量伪造因子,则有可能只更改一个元素,并意外创建一个单独的新级别。

在进行统计分析和实际操作时,因子非常棒探索数据。然而,在此之前,当人们阅读、清理、故障排除、合并和一般操作数据时,因素是一件非常痛苦的事情。最近,就像过去几年一样,许多功能都得到了改进,以更好地处理因素。例如,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的字符串函数非常容易使用,而且逻辑性很强。因此,在操作时,我通常更喜欢字符而不是因子。

tapply(和aggregate)依赖于因子。这些函数的信息努力比非常高

例如,在一行代码(下面调用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

有序因素是可怕的,如果我碰巧喜欢桔子,讨厌苹果,但不介意葡萄,我不需要管理一些奇怪的指数来这么说:

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", ]

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

考虑一些例子。对于在美国各地收集的一些数据,该州应作为一个因素进行记录。在这种情况下,没有从特定州收集到任何案例这一事实是相关的。可能有来自该州的数据,但发生了(无论出于何种原因,这可能是利益原因)不可能。如果收集了家乡,它将不是一个因素。没有预先规定的可能的家乡。如果数据是从三个城镇而不是全国收集的,则该城镇将是一个因素:一开始有三个选择,如果在这三个城镇中的一个城镇中没有发现相关案例/数据,则是相关的t

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

Factors是一种优秀的“独特情况”徽章引擎。我已经重建了很多次,尽管偶尔有一些皱纹,他们是非常强大的

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
库(dplyr)

d所以你真的只是用它们来节省存储空间。这是有道理的。至少过去是这样;-)。但是几个R版本之前字符存储被重写为内部散列,所以这个历史参数的一部分现在是无效的。仍然因子对分组和建模非常有用。根据
?factor
它是R-2.6.0,它说,“整数值存储在4个字节中,而对字符串的每个引用都需要4或8个字节的指针。”如果字符串需要8个字节,转换为因子会节省空间吗?N@Eduardo我得到4Kb vs 4.2Kb。对于
N=100000
我得到391.5KB vs 391.8KB。因此因子占用的内存很少。有使用因子的统计分析示例吗?现在有一个base-R函数
droplevels()
。默认情况下,它不会对因子重新排序
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", ]
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