for循环的迭代可以适用于任何向量。这使循环比其他语言更加通用,但是也会使一些人困惑:
nums <- seq(-1, 1, by=.01) ans <- NULL for(i in nums) ans[i] <- i^2有两处错误。你应该意识到我们已经在第二轮回遇到过了(但失败了),ans的索引并不是我们期望的那样。最好这样做:
nums <- seq(-1, 1, by=.01) ans <- numeric(length(nums)) for(i in seq(along=nums)) ans[i] <- nums[i]^2再进一步,当然,应该避免循环。在这个示例中是这样的,在真实的应用中就不一定了。
这样一个循环:
for(i in 0:9) { this.x <- x[i] ...不会按照预期那样。尽管C和其他一些语言的索引从0开始,R是从1开始的。幸运的是在这个案例中,索引为0是允许的,但是没有做我们想要的操作。
下述循环中有两个”i”。
> for(i in 1:3) { cat("i is", i, "\n") i <- rpois(1, lambda=100) cat("end iteration", i, "\n") } i is 1 end iteration 93 i is 2 end iteration 91 i is 3 end iteration 101循环体中所创建的i在迭代的过程中被使用,但是并没有改变下一次迭代的迭代控制的i。这和其他很多语言不同(包括S+)。
这是R很难被搞混的证据,但是这样的代码毫无疑问会迷惑人类。所以避免吧。
我想说的并不是第二个或者第三个命令,但是将它们混在一起将使你得到错误的结果。
不要混淆:
character(0)和
""第一个是一个长度为0的向量,如果有的话,它的元素是字符型的。第二个是一个长度为1的向量,它的元素是一个空的字符串。
函数nchar()作用在第一个对象上是一个长度为0的数值型向量,作用在第二个上是0—意思是长度为1的向量它的第一个且仅有的元素是0.
> nchar(character(0)) numeric(0) > nchar("") [1] 0字符型的数据中会有缺失值。在正常输出的缺失值是:NA;但是当没有使用引号时,会这样输出:<NA>。和"NA"区分。
> cna <- c(’missing value’=NA, ’real string’=’NA’) > cna missing value real string NA "NA" > noquote(cna) missing value real string <NA> NANA作为一个字符串确实是存在的。比如金融行业中的Nabisco,地理中的North America,甚至化学中的sodium。尤其是将数据读入R时,字符串的NA将会变为缺失值。有一个代表着缺失值的名字确实是已经令人不愉快的经历。
如果在字符向量中有缺失值,当对这个向量进行操作时,你或许需要采取一些避免措施。
> people <- c(’Alice’, NA, ’Eve’) > paste(’hello’, people) [1] "hello Alice" "hello NA" "hello Eve" > ifelse(is.na(people), people, paste(’hello’, people)) [1] "hello Alice" NA "hello Eve"有些人面对R的大小写敏感时,总是很难适应。大小写敏感是意见好的事情。The case of letters REALLy doEs MakE a diFFerencE.
作用域问题在R中不是很常见因为R使用了对几乎所有情况都很直观的作用域规则。作用域问题经常在将S+代码移植到R中发生。
或许你想知道作用域是什么意思。在评估器中,如果在某一点需要一个有确定名字的对象比如z,然后我们需要直到到哪去寻找z。作用域就是去哪寻找的规则集合。
这是一个简单的例子:
> z <- ’global’ > myTopFun function () { subfun <- function() { paste(’used:’, z) } z <- ’inside myTopFun’ subfun() } > myTopFun() [1] "used: inside myTopFun"在函数中被使用的z。让我们考虑一下什么不会发生。在函数subfun()被定义的那一个时间点,仅存的z是那个全局环境中的。什么时候对象被赋值不重要。什么地方对象被赋值才重要。同等重要的是当这个函数执行的时候的相关环境。
最可能出现作用域问题的地方是建模函数。 我们分析一下一下示例。
> scope1 function () { sub1 <- function(form) coef(lm(form)) xx <- rnorm(12) yy <- rnorm(12, xx) form1 <- yy ~ xx sub1(form1) } > scope1() (Intercept) xx -0.07609548 1.33319273 > scope2 function () { sub2 <- function() { form2 <- yy ~ xx coef(lm(form2)) } xx <- rnorm(12) yy <- rnorm(12, xx) sub2() } > scope2() (Intercept) xx -0.1544372 0.2896239scope1()和scope2()作用相同。但是scope3()不同—它跳出了自然嵌套的环境。
> sub3 function () { form3 <- yy ~ xx coef(lm(form3)) } > scope3 function () { xx <- rnorm(12) yy <- rnorm(12, xx) sub3() } > scope3() Error in eval(expr, envir, enclos) : Object "yy" not found这里的一个教训是调用函数没有找到。(技术层面,这是一个动态调用而不是R使用的词典调用。)
当然有解决方案。scope4()通过告诉在哪里寻找代码涉及的数据来解决这个问题。
> sub4 function (data) { form4 <- yy ~ xx coef(lm(form4, data=data)) } > scope4 function () { xx <- rnorm(12) yy <- rnorm(12, xx) sub4(sys.nframe()) } > scope4() (Intercept) xx 0.6303816 1.0930864另一种可能的方法是改变代码的环境:
> sub5 function (data) { form5 <- eval(substitute(yy ~ xx), envir=data) coef(lm(form5)) } > scope5 function () { xx <- rnorm(12) yy <- rnorm(12, xx) sub5(sys.nframe()) } > scope5() (Intercept) xx 0.1889312 1.4208295解决方案的应该注意一些事情—并不是所有的建模函数遵循参数的规则。