8.2 喀迈拉(no.1~no.10)
8.2.1 数字到因子到数字
一般情况下尽管因子不会涉及到数字,但是它们可以。在这种情况下,我们会有更多的困惑。
> as.numeric(factor(101:103))
[1] 1 2 3
如果你期望这样:
[1] 101 102 103
好耻辱啊。
如果你的因子代表数字,你要从因子里恢复这些数字,那么你需要一个曲线救国方案。
as.numeric(as.character(factor(101:103)))
稍微更有效,但难以记住的是:
as.numeric(levels(f))[f]
f是一个因子。
8.2.2 输出因子
在因子上使用函数cat()将仅仅输出核心数据:
> cat(factor(letters[1:5]))
1 2 3 4 5>
8.2.3 意外情况:数字变成因子
当使用read.table()或者此类函数,一列数字类型的数据被以因子的形式读入太常见了。如果na.strings
没有被合理地设置,如果在列上有一个假的入口,或者如果有其他很多的情况,就会发生。
这无异于一包炸药。
这些数据被认为是数字。事实上确实是数字(至少是排序的),但决然不是我们预期的数字。因此你可以使用这些可以“工作”的数据但只会产生完全的垃圾。
当处理这些数据,这样:
as.numeric(as.character(x))
保证你排除问题。如果x已经是一个正确的数字,那么这个除了浪费一点时间外别无副作用。如果x意外地是一个因子,那么这将会是正确的数字(最少在绝大多情况下—取决于它为什么称为因子可能是有一些错误的缺失值。)
8.2.4 剔除因子级别
> ff <- factor(c(’AA’, ’BA’, ’CA’))
> ff
[1] AA BA CA
Levels: AA BA CA
> ff[1:2]
[1] AA BA
Levels: AA BA CA
注意到即使在向量中仅仅有两个元素出现,这里仍然有三个级别。级别不会自动地被剔除通常是一个好的事情—因子有它可以包含的可能的级别而不是仅仅包含它已经包含的级别。
有时你想让那些被剔除的的级别不在出现。有几种方法:
> ff[1:2, drop=TRUE]
[1] AA BA
Levels: AA BA
> factor(ff[1:2])
[1] AA BA
Levels: AA BA
如果f0是已经含有那些你想剔除的没有用的级别,你可以:
f0 <- f0[drop=TRUE]
8.2.5 合并级别
我们已经知道,奇怪的事情将会在合并级别的时候发生。一个安全的方法是重新创建一个因子对象。下边我们把单个字母变为辅音分类:
> flet <- factor(letters[c(1:5, 1:2)])
> flet
[1] a b c d e a b
Levels: a b c d e
> ftrans <- c(a=’vowel’, b=’consonant’, c=’consonant’,d=’consonant’, e=’vowel’)
> fcv <- factor(ftrans[as.character(flet)])
> fcv
[1] vowel consonant consonant consonant vowel vowel consonant
Levels: consonant vowel
或许更常用的是合并一些级别,但是将其他的单独留下:
> llet <- levels(flet)
> names(llet) <- llet
> llet
a b c d e
"a" "b" "c" "d" "e"
> llet[c(’a’, ’b’)] <- ’ab’
> llet
a b c d e
"ab" "ab" "c" "d" "e"
> fcom <- factor(llet[as.character(flet)])
> fcom
[1] ab ab c d e ab ab
Levels: ab c d e
8.2.6 不要在因子上使用下标
> x6 <- c(s=4, j=55, f=888)
> x6[c(’s’, ’f’)]
s f
4 888
> x6[factor(c(’s’, ’f’))]
j s
55 4
8.2.7 不要在ifelse
中使用因子
> ifelse(c(TRUE, FALSE, TRUE), factor(letters),factor(LETTERS))
[1] 1 2 3
> ifelse(c(TRUE, FALSE, TRUE), factor(letters), LETTERS)
[1] "1" "B" "3"
(回想一下,ifelse输出的长度总是第一个参数的长度。如果你期待第一个参数被复制,你最好不要。)
8.2.8 不要在c
中使用因子
c(myfac1, myfac2)
仅仅给你整型代码的合成向量。毫无疑问可以书写对于因子的c的方法,但是会比较复杂—因子的级别不需要匹配。这将得不偿失。这是一个R不会过分有帮助的示例。对于手头的确定的情况,这样做组合是有道理的。
另一个没有对于因子的c函数的原因是c被用来其他可以简化对象的情况。
> c(matrix(1:4, 2))
[1] 1 2 3 4
c在因子上的操作和这个是一致的。
一个普遍好的方法是:
c(as.character(myfac1), as.character(myfac2))
或者对于上述表达式的更加相似的因子。另外一种可能的方法是:
unlist(list(myfac1, myfac2))
比如:
> unlist(list(factor(letters[1:3]), factor(LETTERS[7:8])))
[1] a b c G H
Levels: a b c G H
最后的解决方案对于已排序的因子不适用。
8.2.9 有序排序
当你在创建有序因子时需要主意了:
> ordered(c(100, 90, 110, 90, 100, 110))
[1] 100 90 110 90 100 110
Levels: 90 < 100 < 110
> ordered(as.character(c(100, 90, 110, 90, 100, 110)))
[1] 100 90 110 90 100 110
Levels: 100 < 110 < 90
自动排序是按照字符的字典顺序进行的。通常这是有意义的,但在这个案例中不适用。(注意排序或许取决于你的定位。)你总是可以指定级别以有一个直接的控制。
如果你试着去排序一个因子, 你也会遇到相同的问题。
8.2.10 标签和被剔除的级别
标签的数量和级别的数量必须相同。看起来是个好的规则。在函数中也是这样,但是没必要在最后。问题是有些值被剔除了。
> factor(c(1:4,1:3), levels=c(1:4,NA), labels=1:5)
Error in factor(c(1:4, 1:3), levels = c(1:4, NA), ... :
invalid labels; length 5 should be 1 or 4
> factor(c(1:4,1:3), levels=c(1:4,NA), labels=1:4)
[1] 1 2 3 4 1 2 3
Levels: 1 2 3 4
> factor(c(1:4,1:3), levels=c(1:4,NA), labels=1:5,exclude=NULL)
[1] 1 2 3 4 1 2 3
Levels: 1 2 3 4 5
当然我骗你了。标签的数量可以是1也可以是级别的数量:
> factor(c(1:4,1:3), levels=c(1:4,NA), labels=’Blah’)
[1] Blah1 Blah2 Blah3 Blah4 Blah1 Blah2 Blah3
Levels: Blah1 Blah2 Blah3 Blah4