因子
值得注意的是,在默认情况下,数据框会以更有效地利用内存的方式来存储数据。但
有时,这种存储方式会导致意想不到的问题。
例如,当我们用一个字符向量作为创建数据框的列时,R 会默认将其转换成因子,相
同值只存储一次,以免重复存储占用过多内存。因子本质上是一个带有水平(level)属性
的整数向量,其中“水平”是指我们事前确定的可能取值的有限集合。
我们可以通过对已经创建的数据框 persons 调用 str( )来说明:
str(persons)
## 'data.frame': 3 obs. of 4 variables:
## $ Name : Factor w/ 3 levels "Ashley","Jennifer",..: 3 1 2
## $ Gender: Factor w/ 2 levels "Female","Male": 2 1 1
## $ Age : num 24 25 23
## $ Major : Factor w/ 3 levels "Computer Science",..: 2 3 1
正如我们所看到的,姓名(Name)、性别(Gender)和专业(Major)不是字符向量
而是因子。因为性别(Gender)只可能是女(Female)或男(Male),所以它被表示为
一个因子是合理的。显然使用两个整数表示这两种水平要比即使取值重复也全部保存下来
的字符向量更加有效。
然而,如果某些列并不限于几个可能的取值,使用因子可能会引起问题。例如,我们
想在 persons 中设置一个名字。
persons[1, "Name"] <- "John"
## Warning in `[<-.factor`(`*tmp*`, iseq, value = "John"): invalid factor
## level, NA generated
persons
## Name Gender Age Major
## 1 <NA> Male 24 Finance
## 2 Ashley Female 25 Statistics
## 3 Jennifer Female 23 Computer Science
此时,出现了一个警告。之所以出现警告,是因为在最初设定 Name 这一列时,相应
的水平集合中并没有 John 这个词。因此我们无法给第一个人赋予一个不存在的名字。将
任意一个 Gender 设置成 Unknown 时也会出现同样的情况,原因是一样的。当我们定义
一个数据框时,用一个字符向量作为数据框的一列,该列将默认被转换为因子,其取值只
能从由对应字符向量的唯一值构成的水平集合中选取。
有时候这种情况令人非常恼火。特别是在内存已经很便宜的今天,这种设定真没有多
大帮助。避免这种情况最简单的方式是在使用 data.frame()创建一个数据框时,设置
stringsAsFactors = FALSE:
persons <- data.frame(Name = c("Ken", "Ashley", "Jennifer"),
Gender = factor(c("Male", "Female", "Female")),
Age = c(24, 25, 23),
Major = c("Finance", "Statistics", "Computer Science"),
stringsAsFactors = FALSE)
str(persons)
## 'data.frame': 3 obs. of 4 variables:
## $ Name : chr "Ken" "Ashley" "Jennifer"
## $ Gender: Factor w/ 2 levels "Female","Male": 2 1 1
## $ Age : num 24 25 23
## $ Major : chr "Finance" "Statistics" "Computer Science"
如果我们真的想让一个因子对象发挥它的作用,可以直接在特定的列上调用 factor( )
函数,就像 Gender 那一列。