数据科学与R语言

4. 函数

2020-04-15  本文已影响0人  kkkkkkang

Ok,开始新的一章。基本的我就不写了,只写应该注意的地方和坑。代码基本都是来源于书上,少部分是我自己加上去的

> j <- function() {
  if (!exists("a")) {
    a <- 1
  } else {
    a <- a + 1
  }
  a
}
> j()
[1] 1
> j()
[1] 1
#因为每次调用这个函数都会创建一个新环境,函数不可能知道上次被调用时发生了什么,每次调用都是独立的
> f <- function() x
> x <- 15
> f()
[1] 15
> x <- 20
> f()
[1] 20
#然而,这样函数就不是独立的了,可以使用codetools::findGlobals()查看一个函数额所有外界依赖关系
> f <- function() x + 1
> codetools::findGlobals(f)
[1] "+" "x"
#使用emptyenv()清空环境不现实,这样你连"+"都用不了了。所以这样别人就有可能使坏了
#比如:趁你不在,把"("的这个函数给改掉—有1/10的概率得到比输入值大1的数
> `(` <- function(e1) {
  if (is.numeric(e1) && runif(1) < 0.1) {
    e1 + 1
  } else {
    e1
  }
}
> replicate(50, (1 + 2))
> replicate(50, (1 + 2))
 [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 3 3 3 3 3 3 3 4 3 3 3 3 4 3 3 3 3 3 3 3 3 3
[39] 3 3 3 3 3 3 4 3 3 3 4 3
#看看,是的吧。解决方法很简单
> rm("(")
> replicate(50, (1 + 2))
 [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
[39] 3 3 3 3 3 3 3 3 3 3 3 3
#重归于好,哈哈哈。这里不是教人使坏,其实是警示大家在开始R会话之前,尽量清空之前对话的数据
> rm(list = ls())
> f <- function(x) {
+     f <- function(x) {
+         f <- function(x) {
+             x ^ 2
+         }
+         f(x) + 1
+     }
+     f(x) * 2
+ }
> f(10)
#在脑子里过一下这个会得到什么结果
好吧,答案是202
#解答思路:最内层函数要向外找变量值10,f(x) +1 值就成了101,然后f(x)*2就是202
> `%foo%` <- `+`
> 2 %foo% 4
[1] 6
> `%mul%` <- `*`
> 2 %foo% 4 %mul% 3
[1] 18
#默认优先级是从左到右的,调整优先级,加括号就行了
> 2 %foo% (4 %mul% 3)
[1] 14
> `%mul%`(3,4)
[1] 12
x <- 10; y <- 5
x + y
#> [1] 15
`+`(x, y)
#> [1] 15

for (i in 1:2) print(i)
#> [1] 1
#> [1] 2
`for`(i, 1:2, print(i))
#> [1] 1
#> [1] 2

if (i == 1) print("yes!") else print("no.")
#> [1] "no."
`if`(i == 1, print("yes!"), print("no."))
#> [1] "no."

x[3]
#> [1] NA
`[`(x, 3)
#> [1] NA

{ print(1); print(2); print(3) }
#> [1] 1
#> [1] 2
#> [1] 3
`{`(print(1), print(2), print(3))
#> [1] 1
#> [1] 2
#> [1] 3

上面这个思想和apply结合可以自编函数来处理每个元素,实现想要的功能

> add <- function(x, y) x + y
> sapply(1:10, add, 3)
 [1]  4  5  6  7  8  9 10 11 12 13
> sapply(1:5, `+`, 3)
[1] 4 5 6 7 8
> sapply(1:5, "+", 3)
[1] 4 5 6 7 8
> x <- list(1:3, 4:9, 10:12)
> sapply(x, "[", 2)
[1]  2  5 11
> sapply(x, function(x) x[2])
[1]  2  5 11
#使用参数列表来传递函数参数
> args <- list(1:10, na.rm = TRUE)
> do.call(mean, args)
[1] 5.5
#等同于
> mean(1:10,na.rm = TRUE)
[1] 5.5
#默认参数
> f <- function(a = 1, b = 2) {
  c(a, b)
}
> f()
#> [1] 1 2
#默认参数可以使用其它参数来求值
g <- function(a = 1, b = a * 2) {
  c(a, b)
}
g()
#> [1] 1 2
g(10)
#> [1] 10 20
#默认参数甚至可以是隐藏在函数内部的变量(这并不推荐)
h <- function(a = 1, b = d) {
  d <- (a + 1) ^ 2
  c(a, b)
}
h()
#> [1] 1 4
h(10)
#> [1]  10 121
#像上面这种,默认参数需要很长的计算才能得到,通常建议使用missing()函数判断,有需要再计算。
#缺点:不阅读文档就不知道那个参数是必须的。可以把默认参数设置成NULL,is.null()去判断参数是否设置了
> a <- function(x){
  for (i in 1:x){
    print(i)
    if (i == 3){
      stop("Error:3 is an error number")
    }
  }
}
> a(4)
[1] 1
[1] 2
[1] 3
Error in a(4) : Error:3 is an error number
> f <- function(a,b){
+   print(a)
+ }
> f(2)
[1] 2
> f_1 <- function(a,b){
+   print(a)
+   print(b)
+ }
> f_1(8)
[1] 8
Error in print(b) : 缺少参数"b",也没有缺省值
************************************************************
> a <- NULL
> if (is.null(a)) stop("a is null")
错误: a is null
> !is.null(a) || stop("a is null")
错误: a is null
> is.null(a) || stop("a is null")
[1] TRUE

...参数:它可以传递一个函数的参数到另一个函数(可以利用这个特性修改已知函数的参数,而不必列出所有原函数的参数);当传递到函数的参数数量不能确定的时候,它必须被使用

#用来传参
> new_plot <- function(x,y,type = "s",...){
  plot(x,y,...)
}
#参数个数不确定
> num <- function(...,sep = "_"){
+   paste(...,sep = sep)
+ }
> num(1,2,3)
[1] "1_2_3"
> f <- function(x) {
+     x$a <- 2
+     x
+ }
> x <- list(a = 1)
> f(x)
$a
[1] 2
> x$a
[1] 1
f1 <- function() 1
f2 <- function() invisible(1)
f1()
#> [1] 1
f2()
f1() == 1
#> [1] TRUE
f2() == 1
#> [1] TRUE
********************************************************
#可以使用括号,强制显示
(f2())
#> [1] 1
#最常用的隐藏返回值的函数应该是"<- "了,这样可以把一个值赋给多个变量
a <- b <- c <- d <- 2

on.exit()前面一章已经说过了,需要注意的是:如果在一个函数中使用多个on.exit(),一定要加上参数add = TRUE。不加的话,每次运行on.exit()后,它将重写退出表达式

上一篇 下一篇

猜你喜欢

热点阅读