8.3 魔鬼(no.21~no.30)
8.3.21 维度为11的数组
数组的维度可以是任何正数(内存的模和向量长度限制)。特别的,维度为1也是可能的。它的长相和表现总是像一个平的向量。总是。
这是个它们不是这样的例子:
> df2 <- data.frame(x=rep(1, 3), y=tapply(1:9,factor(rep(c(’A’, ’B’, ’C’), each=3)), sum))
> df2
x y
A 1 6
B 1 15
C 1 24
> tapply(df2$y, df2$x, length)
1
3
> by(df2$y, df2$x, length)
INDICES: 1
[1] 1
> by(as.vector(df2$y), df2$x, length)
INDICES: 1
[1] 3
tapply
返回一个数组,特别的它也可以返回一个维度为1的数组—df2$y
的情况。函数by
在当被赋予一个维度为1的数组时产生一个对于我们没有认为我们已经问了的问题的正确答案。
维度为1的数组既不是矩阵也不是(精确地说)平的向量。
8.3.22 数据框的by
函数by
本质上讲是tapply
的一个对于数据框的漂亮的版本。“对于数据框”是一个重要的限制。如果你对by
进行调用时,第一个参数不是一个数据框,你可能要陷入麻烦了。
> tapply(array(1:24, c(2,3,4)), 1:24 %% 2, length)
0 1
12 12
> by(array(1:24, c(2,3,4)), 1:24 %% 2, length)
Error in tapply(1:2L, list(INDICES = c(1, 0, 1, 0, 1, 0, 1, :
arguments must have same length
在这个例子中我们幸运的是有错误提示,在8.3.21我们并没有这么幸运了。
8.3.23 迷失的反引号
函数定义中一个迷失的反引号可以造成错误信息:
symbol print-name too long
反引号有时(太)靠近tab key 和/或者 escape key。它也靠近最小尺寸,因此容易被忽视。
8.3.24 数组维度计算
有些时候,矩阵的创建没有按照我们的真实意向而失败:
> mf <- matrix(runif((2 - .1) / .1 * 5), ncol=5)
Warning message: data length [94] is not a sub-multiple or
multiple of the number of rows [19] in matrix
注意到矩阵已经被创建—有一个警告而非错误—矩阵的创建几乎很少不合适。如果你忽视这个警告,在后边可能就会有结果了。
我们来研究一下这个:
> (2 - .1) / .1
[1] 19
> (2 - .1) / .1 - 19
[1] -3.552714e-15
> as.integer((2 - .1) / .1)
[1] 18
当R强制将一个浮点数变为一个正整数,它是截断(truncates)的而非环形(rounds)。
这个故事的寓意是round
可以是一个方便的函数来使用。其实这个问题真的是属于第一轮回的(page 19),但是微妙性使其很难找到问题所在。
8.3.25 替换矩阵的部分元素
我们有两个矩阵:
> m6 <- matrix(1:6, 3)
> m4 <- matrix(101:104, 2)
> m6
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
> m4
[,1] [,2]
[1,] 101 103
[2,] 102 104
我们的任务是创造一个新的和m6相似的矩阵,其中的一些行被m4的前几行所代替。这是一个自然的做法:
> m6new <- m6
> m6new[c(TRUE, FALSE, TRUE), ] <- m4[1,]
> m6new
[,1] [,2]
[1,] 101 101
[2,] 2 5
[3,] 103 103
我们认为在这种自然方法下的行的结果是有问题的。问题是这并不是R的方式,忽略了上下文。
一个得到我们想要的结果是:
> s6 <- c(TRUE, FALSE, TRUE)
> m6new[s6, ] <- rep(m4[1,], each=sum(s6))
> m6new
[,1] [,2]
[1,] 101 103
[2,] 2 5
[3,] 101 103
8.3.26 保留字
R是一门语言。正因为如此,就会有你不能用作对象名的保留字。如果下面的命令能工作的话,也许你能想象到后果是什么:
FALSE <- 4
你可以用这个来查看完整的保留字列表:
?Reserved
8.3.27 return
是一个函数(I)
和其他一些语言不同,return
是一个函数返回你想要的对象。下面的结构不会返回你想要的结果:
return (2/5) * 3:9
它返回0.4,忽略了后面的东西。
8.3.28 return
是一个函数(II)
return
是一个函数,不是一个保留字。
># kids, don’t try this at home
>return <- function(x) 4 * x
># notice: no error
>rm(return)
8.3.29 批量失败
周五下午你开始批处理作业,你开心地认为星期一早上,在你的手上将有计算了六十几个小时的结果。周一早上却找不到结果。因为在你的代码中有一个错误的逗号,你的任务在一个小时后就失败了。结果不敢保证,但是至少有可能你可以检查错误的逗号和它的队友。一旦你写了自己的代码,粘贴上:
parse(file=’batchjob.in’)
如果有任何的语法错误,你将在得到一个错误(第一个)和错误的地点。如果没有语法错误,你将得到一个解释(一个大大的解释)。
8.3.30 损坏的.RData
有时因为一个损坏的.RData
,R在特定的目录下无法启动。如果.RData
有重要的数据,这将是一个坏消息。
有时可能是这个数据依赖的一个包没有被加载进来。无论如何,这就是问题,你可以在vanilla
模式下启动R
(首先重命名这个数据也是好的想法)然后试着加载数据。
原则上,检查.RData
中有什么样的对象并且提取这个对象的一些例子。然而,我不知道用什么工具做这个。