在因子中缺失值当然是有意义的。完全有可能是我们不知道这个特定的条目属于什么类型。
> f1 <- factor(c(’AA’, ’BA’, NA, ’NA’))
> f1
[1] AA BA NA
Levels: AA BA NA
> unclass(f1)
[1] 1 2 NA 3
attr(,"levels")
[1] "AA" "BA" "NA"
正如在8.1.67轮回所述,缺失值和”NA”还是有区别的。在f1有一个种类是字符串类型的”NA”。缺失值由
而不是NA来表示(在引号没有使用的情况下用以区别”NA”)。
含有缺失值是很有可能的。可以通过改变默认的exclude
参数来实现:
> f2 <- factor(c(’AA’, ’BA’, NA, ’NA’), exclude=NULL)
> f2
[1] AA BA NA
Levels: AA BA NA NA
> unclass(f2)
[1] 1 2 4 3
attr(,"levels")
[1] "AA" "BA" "NA" NA
和f1
不同,f2
的核心数据不含有缺失值。
让我们真正地进入这只野兽的肚皮里面吧。
> f3 <- f2
> is.na(f3)[1] <- TRUE
> f3
[1] BA NA
Levels: AA BA NA NA
> unclass(f3)
[1] NA 2 4 3
attr(,"levels")
[1] "AA" "BA" "NA" NA
我们有了一个缺失值的级别,我们在核心数据中同样有了一个缺失值。
总结一下,有两种方法缺失值可以进入到一个因子:
> xdf3 <- data.frame(a=3:2, b=c(’x’, ’y’))
> as.character(xdf3[1,])
[1] "3" "1"
这是一个强制将因子变为字符的版本。获得正确答案的一个方法是使用as.matrix
:
> as.character(as.matrix(xdf3[1,]))
[1] "3" "x"
我不确定如果你强制将一个数据框中多于一行的数据转换成字符是喜还是忧:
> as.character(xdf3)
[1] "c(3, 2)" "c(1, 2)"
如果一个数据框的列含有因子或者字符,那么强制转换成一个矩阵将自动地给你返回字符:
> as.matrix(xdf3)
a b
[1,] "3" "x"
[2,] "2" "y"
当下标指向对象中不存在的值是,返回值往往有代码的环境决定:
> c(b=1)[c(’a’, ’b’)]
b
NA 1
> list(b=1)[c(’a’, ’b’)]
$
NULL
$b
[1] 1
> matrix(1:2, 2, 1, dimnames=list(NULL, ’b’))[,c(’a’, ’b’)]
Error: subscript out of bounds
> matrix(1:2, 1, 2, dimnames=list(’b’, NULL))[c(’a’, ’b’),]
Error: subscript out of bounds
> data.frame(b=1:2)[, c(’a’, ’b’)]
Error in "[.data.frame"(data.frame(b = 1:2), , c("a", "b")) :
undefined columns selected
> data.frame(V1=1, V2=2, row.names=’b’)[c(’a’, ’b’),]
V1 V2
NA NA NA
b 1 2
有些人好奇为什么这个外来的条目的名字是NA
却不是"a"
。答案是并没有迹象表明在这个对象中”a”不是一个名字。
所举例子都是基于字符的下标,对于数值和逻辑型的下标有相似的结果。
有两个我们将会使用到的向量:
> a <- c(rep(1:4, 3), NA, NA)
> b <- rep(1:2, 7)
> b[11:12] <- NA
> a
[1] 1 2 3 4 1 2 3 4 1 2 3 4 NA NA
> b
[1] 1 2 1 2 1 2 1 2 1 2 NA NA 1 2
现在我们想要在a
的基础上创建anew
并满足以下条件:当a
的值小于2或者大于3并且b
等于1时,anew
的值为101。
> anew <- a
> anew[(a < 2 | a > 3) & b == 1] <- 101
> anew
[1] 101 2 3 4 101 2 3 4 101 2 3 4 NA NA
在anew
中有三个值改变了;让我们再试一次但是给这三个改变的值不同的数值:
> anew2 <- a
> anew2[(a < 2 | a > 3) & b == 1] <- 101:103
Error: NAs are not allowed in subscripted assignments
现在我们得到了一个错误。如果需要被赋值进入向量的值的长度大于1时,对缺失下标的赋值是不能确定的。R机智地拒绝执行(可能令人泄气)。然而这也是由办法解决的:
> anew2[which((a < 2 | a > 3) & b == 1)] <- 101:103
> anew2
[1] 101 2 3 4 102 2 3 4 103 2 3 4 NA NA
which
高效地视NA
如同FALSE
。
但是在anew
和anew2
中仍旧有一个问题。a
的第12个元素是4(比3大),b
的第12个元素是NA
。因此我们不知道anew
的第12个元素应不应该被改变。anew
的第12个元素应该是NA
:
> anew[is.na(b) & (a < 2 | a > 3)] <- NA
> anew
[1] 101 2 3 4 101 2 3 4 101 2 3 NA NA NA
> letters[c(2,3)]
[1] "b" "c"
> letters[c(2,NA)]
[1] "b" NA
> letters[c(NA,NA)]
[1] NA NA NA NA NA NA NA NA NA NA NA NA
[13] NA NA NA NA NA NA NA NA NA NA NA NA
[25] NA NA
因为默认情况下NA
是逻辑的—最具体的模式(看8.1.8),因此最后一个命令是逻辑的下标取代了数值型的下标。逻辑下标化会自动地复制为对象的长度。
if
中的缺失值if(NA) { # creates error
在if的条件为NA
是一个非常常见的错误。当它出现时,通常以不可见的形式出现。需要进行debug
。
一个替代的名称可以是"or 或者 oror"
。
有两个"and"
操作和两个"or"
操作。
– '&&' and '||' 适用于if
– '&' and '|' 适用于ifelse
'&&'
和'||'
,和if
一样,期望单独元素的输入。因为它们仅仅处理单独元素,它们可以超近道。如果第一个(左边的)元素的答案已经知晓,就没有必要去评估第二个了。
> if(TRUE || stop()) 4 else 5
[1] 4
> if(TRUE && stop()) 4 else 5
Error:
> if(FALSE || stop()) 4 else 5
Error:
> if(FALSE && stop()) 4 else 5
[1] 5
这个可以被用来确保进行测试是安全的:
> if(ncol(x) > 6) { ...
Error in if (ncol(x) > 6) : argument is of length zero
> if(is.matrix(x) && ncol(x) > 6) { ... # okay
注意到最后一行的x并没有一数据框举例。如果你想在数据框和矩阵上都可以,检测dim(x)
将会是一个方法。
仅仅是因为'&&'
和'&'
有相似的用意,不要认为'=='
和'='
也就是相似的。完全不同。
幸运的是R在你输入的时候就避免你出现这样的错误:
> if(x = 7) { ...
Error: unexpected ’=’ in "if(x ="
> if(x == 7) { ... # okay
不同之处在于:
'=='
是一个逻辑操作检查是否相等。'='
是一个赋值操作和'<-'
相似(但是看看8.2.26)。is.integer
is.integer
检验数据是以什么形式存储的,但是不会检测数字是否是逻辑数字:
> is.integer(c(4, 0, 3))
[1] FALSE
关键点在于,几乎可以确定的,你不需要关心一个对象是否是以integer
的形式存储。当你需要将此数据传送到C
或者Fortran
时是很重要的。否则你可以让R
关心细节来减少困难这样你可以考虑其他更高层次的东西。
如果你真的想要整型数据(以整型的形式存储),使用"L"
:
> is.integer(c(4L, 0L, 3L))
[1] TRUE
> is.integer(c(4L, 0L, 3))
[1] FALSE
操作符":"
是在R
中少有的几个产生整型数据的地方之一:
> is.integer(1:3)
[1] TRUE
> is.integer(c(1:3, 4))
[1] FALSE
> is.integer(c(1:3, 4:4))
[1] TRUE
参考其他编程语言的经验,你或许希望:
> is.integer( 4. )
[1] FALSE
> is.integer( 4 )
[1] FALSE
第一个的结果是FALSE
而第二个的结果是TRUE
。当你使用小数点是意味着你想要一个浮点数而不是一个整型数。可以看到R
对浮点数有癖好。你可以强制将其转换成integer
,但是(几乎)考虑清楚你想要什么:
> as.integer(c(0, 1, -2.99, 2.99))
[1] 0 1 -2 2
is.numeric
,as.numeric
用is.numeric
来检验一个整型向量的结果是TRUE
。然而,as.numeric
将整型的存储类型改变为双精度的存储类型。如果你很关心它变为整型,使用as.integer
。
> is.integer(c(4L, 0L))
[1] TRUE
> is.numeric(c(4L, 0L))
[1] TRUE
> is.integer(as.numeric(c(4L, 0L)))
[1] FALSE