8.3 魔鬼(no.11~no.20)

8.3 魔鬼(no.11~no.20)

8.3.11 integrate中的非向量化函数

integrate函数期待一个向量化的函数。当它给了一个长度是127的参数,它期望得到一个长度是127的答案。如果它没有得到它想要的,它就会表示它的不满:

> fun1 <- function(x) sin(x) + sin(x-1) + sin(x-2) + sin(x-3)
> integrate(fun1, 0, 2)
-1.530295 with absolute error < 2.2e-14
> fun2 <- function(x) sum(sin(x - 0:3))
> integrate(fun2, 0, 2)
Error in integrate(fun2, 0, 2) :
     evaluation of function gave a result of wrong length
In addition: Warning message:
     longer object length is not a multiple of shorter object length in: x - 0:3
> fun3 <- function(x) rowSums(sin(outer(x, 0:3, ’-’)))
> integrate(fun3, 0, 2)
-1.530295 with absolute error < 2.2e-14

fun1是我们想要的的直接了当的实现,但是很难去概括。fun2是模拟fun1的拙略的尝试。fun3是一个使用了outer作为一步使向量化得到正确的答案的适当的实现。

8.3.12 outer的非向量化函数

传递给outer的函数需要向量化(在通常情况下):

> outer(1:3, 4:1, max)
Error in dim(robj) <- c(dX, dY) :
   dims [product 12] do not match the length of object [1] 
> outer(1:3, 4:1, pmax)
    [,1] [,2] [,3] [,4]
[1,]  4    3    2    1
[2,]  4    3    2    2
[3,]  4    3    3    3
> outer(1:3, 4:1, Vectorize(function(x, y) max(x, y)))
    [,1] [,2] [,3] [,4]
[1,]  4    3    2    1
[2,]  4    3    2    2
[3,]  4    3    3    3

函数可以用来转换一个函数(本质上是加加一个循环—向量化函数并没有什么神奇)。

8.3.13 忽视错误

你有一个循环其中一些迭代可能产生一些错误。你想忽略这些错误并让循环继续执行。一个解决方案是使用try

代码:

ans <- vector(’list’, n)
for(i in seq(length.out=n)) 
{
  ans[[i]] <- rpois(round(rnorm(1, 5, 10)), 10)
} 

当所要求的泊松变量的数值为负的情况下会失败。可以这样修改:

ans <- vector(’list’, n)
for(i in seq(length.out=n)) 
{
  this.ans <- try(rpois(round(rnorm(1, 5, 10)), 10))
  if(!inherits(this.ans, ’try-error’)) 
  {
    ans[[i]] <- this.ans
  }
}

另外一个方法是使用tryCatch而不是try

ans <- vector(’list’, n)
for(i in seq(length.out=n)) 
{
  ans[[i]] <- tryCatch(rpois(round(rnorm(1, 5, 10)), 10),
  error=function(e) NaN)
}

8.3.14 意外的全局

让函数在被创造的地方工作是可能的,但是不要在一般下工作。函数中的对象会意外地变为全局的。

> myfun4 <- function(x) x + y
> myfun4(30)
[1] 132
> rm(y)
> myfun4(30)
Error in myfun4(30) : Object "y" not found

函数findGlobals可以高亮全局变量:

> library(codetools)
> findGlobals(myfun4)
[1] "+" "y"

8.3.15 掌控"..."

"..."构造直到你直到这个特技之前你都可以持有这个光滑的东西。一种方法是将其包进一个列表:

function(x, ...) 
{
  dots <- list(...)
  if(’special.arg’ %in% names(dots)) 
  {
    # rest of function
  }
}

另一种方法是使用match.call

function(x, ...) 
{
  extras <- match.call(expand.dots=FALSE)$...
  # rest of function
}

如果你的函数要处理一个参数,那么你或许需要使用do.call

function(x, ...) 
{
  # ...
  dots <- list(...)
  ans <- do.call(’my.other.fun’, c(list(x=x), dots[names(dots) %in% spec]))
  # ...
}

8.3.16 懒惰

R采用懒惰的评估。意思是,函数的参数直到它们需要的时候才会被评估。如果该参数被证明是不需要的,这可以节省时间和内存。

在极度稀有的情况下,一个参数本该评估却没有被评估。
你可以使用force强制克服懒惰。

> xr <- lapply(11:14, function(i) function() i^2)
> sapply(1:4, function(j) xr[[j]]())
 [1] 196 196 196 196
> xf <- lapply(11:14, function(i) {force(i); function() i^2})
> sapply(1:4, function(j) xf[[j]]())
 [1] 121 144 169 196

额外的信用来理解在xr中发生的事情。

8.3.17 懒惰的lapply

lapply不会评估它的FUN参数。大多数情况下你不需要关心。如果该函数是一个泛型函数的话就会更加有效。这样做是更安全的:

lapply(xlist, function(x) summary(x))

比起:

lapply(xlist, summary)

8.3.18 不可见的斗篷

在很少的情况下,结果的可视性或许不是所期望的那样:

> myfun6 <- function(x) x
> myfun6(zz <- 7)
> .Last.value
[1] 7
> a6 <- myfun6(zz <- 9)
> a6
[1] 9
> myfun6(invisible(11))
> myfun7 <- function(x) 1 * x
> myfun7(invisible(11))
[1] 11

8.3.19 默认参数的评估

考虑:

> myfun2 <- function(x, y=x) x + y
> x <- 100
> myfun2(2)
[1] 4
> myfun2(2, x)
[1] 102

一些人会期待上述的两个函数调用的结果是相同的。它们不是。一个函数的一个参数的默认值在函数里边评估,不是在调用函数的环境中。

因此写一个类似下边的函数将不会得到你想要的。

> myfun3 <- function(x=x, y) x + y
> myfun3(y=3)
Error in myfun3(y = 3) : recursive default argument reference

(在你的R的版本中你得到的实际错误信息可能不一样。)

在这个方面最流行的错误是模仿参数的默认值。像这样:

> myfun5 <- function(x, n=xlen) { xlen <- length(x); ...}
> myfun5(myx, n=xlen-2)

xlenmyfun5里边定义,当调用myfun5 的时候是不可以使用xlen的。

8.3.20 sapply简单化

函数sapply“简化”了lapply的输出。并不总是如此简单。意思是,你得到的简单化或许不是你所期望的简单化。不确定性使sapply在函数中使用不是很合适。有时vapply是一个更安全的替代。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值