8.1 幽灵(no.61~no70)

    xiaoxiao2025-04-19  9

    8.1 幽灵(no.61~no70)

    8.1.61 错误的迭代(I)

    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

    再进一步,当然,应该避免循环。在这个示例中是这样的,在真实的应用中就不一定了。

    8.1.62 错误的迭代(II)

    这样一个循环:

    for(i in 0:9) { this.x <- x[i] ...

    不会按照预期那样。尽管C和其他一些语言的索引从0开始,R是从1开始的。幸运的是在这个案例中,索引为0是允许的,但是没有做我们想要的操作。

    8.1.63 错误的迭代(III)

    nam <- c(4, 7) vec <- rep(0, length(nam)) names(vec) <- nam for(i in nam) vec[i] <- 31 vec 4 7 0 0 NA 31 NA NA 31

    8.1.64 迭代神圣不可侵犯

    下述循环中有两个”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很难被搞混的证据,但是这样的代码毫无疑问会迷惑人类。所以避免吧。

    8.1.65 错误的序列

    > seq(0:10) [1] 1 2 3 4 5 6 7 8 9 10 11 > 0:10 [1] 0 1 2 3 4 5 6 7 8 9 10 > seq(0, 10) [1] 0 1 2 3 4 5 6 7 8 9 10

    我想说的并不是第二个或者第三个命令,但是将它们混在一起将使你得到错误的结果。

    8.1.66 空的字符串

    不要混淆:

    character(0)

    ""

    第一个是一个长度为0的向量,如果有的话,它的元素是字符型的。第二个是一个长度为1的向量,它的元素是一个空的字符串。

    函数nchar()作用在第一个对象上是一个长度为0的数值型向量,作用在第二个上是0—意思是长度为1的向量它的第一个且仅有的元素是0.

    > nchar(character(0)) numeric(0) > nchar("") [1] 0

    8.1.67 NA 字符串

    字符型的数据中会有缺失值。在正常输出的缺失值是: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> NA

    NA作为一个字符串确实是存在的。比如金融行业中的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"

    8.1.68 大写

    有些人面对R的大小写敏感时,总是很难适应。大小写敏感是意见好的事情。The case of letters REALLy doEs MakE a diFFerencE.

    8.1.69 作用域(I)

    作用域问题在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是那个全局环境中的。什么时候对象被赋值不重要。什么地方对象被赋值才重要。同等重要的是当这个函数执行的时候的相关环境。

    8.1.70 作用域(II)

    最可能出现作用域问题的地方是建模函数。 我们分析一下一下示例。

    > 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.2896239

    scope1()和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

    解决方案的应该注意一些事情—并不是所有的建模函数遵循参数的规则。

    转载请注明原文地址: https://ju.6miu.com/read-1298233.html
    最新回复(0)