加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

R语言tips之 Functions函数

(2014-05-22 15:42:27)
标签:

it

分类: R语言
我们所说的函数一般是closures, 源自于LISP, 仅仅是为了与R的原函数(primitive function)区分

一、函数共有的属性

closures函数都具有三种属性

body(), 返回函数体,显然跟在console中直接输入函数名一样
formals(), 形参, 如何调用参数, pairlist, 每一个参数对应了一个value,因而可以使用alist改变函数的参数
environment(), 函数中变量的作用环境,如果没有指明函数的环境,默认为Globalenv也就是workspace
这三个属性都可以改变函数
f <- function(xy 1z 2{
    x y z
}
formals(f<- alist(x y 100z 200)
f
## function (x, 100, 200)
## {
##     z
## }
body(f)
## {
##     z
## }
二、原函数
原函数除了上述三个属性,还包括了.Primitive(), 纯粹用c编写, 全都在base包中, 如sum()和.Primitive(“sum”)()一个意思, 貌似不管我们的事
## 显示所有原函数
ls("package:base"all TRUE)
三、作用域
作用域决定了R中符号(symbol)如何去寻值, 两种类型作用域, language level:lexical scoping(词典还是词汇什么什么的作用域实在不知道怎么翻译), 结合在一起来构建函数; 在交互分析中节省type的动态作用域dynamic scoping, computing on the language ?语言计算

词法作用域的寻值方式是由函数的构建方式决定, 通过查看函数的定义就可知道如何寻值, 感觉就是一句话函数的值调用

Advanced R programming对于lexical的说明:

The “lexical” in lexical scoping doesn't correspond to the usual English definition (“of or relating to words or the vocabulary of a language as distinguished from its grammar and construction”) but comes from the computer science term “lexing”, which is part of the process that converts code represented as text to meaningful pieces that the programming language understands. R's lexical scoping is lexical in this sense because you only need the definition of the functions, not how they are called.

四、函数变量寻值

四个基本原则

首先在本函数内部,然后到上一层env,可以是f或者env,直至globalenv,最后是load的其他的package

对于函数

## 返回一个function
j <- function(x{
    y <- 2
    function() {
        c(xy)
    }
}
k <- j(1)
k
## function() {
##         c(x, y)
##     }
## 
k()
## [1] 2
rm(jk)
这是因为函数k记录着自己的作用环境,因为y的值可以捕捉到
五、每一个操作符都是一个函数

To understand computations in R, two slogans are helpful:

Everything that exists is an object.
Everything that happens is a function call.
— John Chambers

曾经用apply的时候经常定义函数function(x)x[2] 其实更简单的是用"[“
x <- list(1:34:910:12)
sapply(x"["2)
## [1]   11
sapply(xfunction(xx[2])
## [1]   11
六、参数

首先匹配名词完全相同, 然后是模糊匹配 可以写一个参数的前缀 模糊匹配强烈反对 代码可读性 如果两个参数前缀一样也会出错, 最后按参数的位
f <- function(abcdefbcde1bcde2{
    list(a abcdefb1 bcde1b2 bcde2)
}
str(f(13b 1))
## Error: argument matches multiple formal arguments
如果参数是list df, do.call, 这个楼主经常用, 其实Reduce()也可以实现, 个人感觉Reduce()还是很强大的, 有兴趣的去"?Reduce"
do.call(meanlist(1:5))
## [1] 3
do.call(cbindlist(c(12), c(23)))
##      [,1] [,2]
## [1,]       2
## [2,]       3

cbin <- function(x)Reduce("cbind"x)
cbin(list(c(12), c(23)))
##      init
## [1,]    2
## [2,]    3
参数缺省值, 在定义函数的时候赋值给参数, 甚至可以在函数内部定义缺省值(蛋疼)
h <- function(a 1b d{
    d <- (a 1)^2
    c(ab)
}
h()
## [1] 4
[1] 4
h(10)
## [1]  10 121
[1] 10 121
如果定义了参数,在调用的时候不用, 在函数定义的时候要定义 missing(arg)函数如何计算,missing()只用于函数的构建 不建议使用missing, 不如设立缺省值NULL, 在函数内部用 is.null(arg)

七、R计算的懒惰性
f <- function(x{
    10
}
system.time(f(Sys.sleep(10)))
##    user  system elapsed
##                   0
因为x并没有没用到,所以函数兵没有执行,可以通过force()来强制执行

f <- function(x{
    force(x)
    10
}
system.time(f(Sys.sleep(10)))
##    user  system elapsed
##                  10
更有趣的一个例子

add <- function(x{
    function(yx y
}
adders <- lapply(1:10add)
adders[[1]](10)
## [1] 20
adders[[10]](10)
## [1] 20
在调用add函数的时候, x并没有被evaluate, 所以直至lapp完成x =10, 在add加一句fix(x)会得到正常结果11:20

还需要注意的是默认参数是在函数内部环境中寻值的
f <- function(x ls()) {
    a <- 1
    x
}

ls() evaluated inside f:
f()
## [1] "a" "x"

ls() evaluated in global environment:
f(ls())
## [1] "add"    "adders" "f"      "h"      "x"
不知道谁会这样定义参数

一个没有被evaluate的参数在R中称为promise pryr::promise_info可以查看promise的信息

lazy这个特性在if语句中非常有用
x <- NULL
if (!is.null(x&& x 0{

}
NULL > 0是长度为0的逻辑向量, 并不能用于if中,甚至有时候可以避免使用if语句
if (is.null(a)) stop("a is null")
## Error: object 'a' not found
!is.null(a|| stop("a is null")
## Error: object 'a' not found
八、…

...代表了所有的其他的参数,可以传递给所调用的函数,也可以是自己定义的参数, 最大的用处就是参数传递,省得把所有参数都写上, 但是错误的参数不会报错(都被…吸收了), 如果哪位童鞋编写过自己的Package"..."应该经常用

九、特殊运算符

大多数函数参数都是在函数名之后, 什么 + -等显然不是, 我们也可以自定义这种特殊运算符,以%开头结尾, 定义函数的时候函数名-引号

替代函数, 通常含有两个参数,用于修改它的一个参数,返回值则是这个已改变的参数对象
"second<-" <- function(xvalue{
    x[2<- value
    x
}
x <- 1:10
second(x<- 5L
x
##  [1]          10
显然names()什么的属于这一类

十、返回值

函数最主要的就是只调用, 只有返回值影响其工作环境,copy-on-modify semantics

env和引用类除外

library引入新的对象, 函数data等
setwd, Sys.setenv, Sys.setlocale 改变环境变量 工作目录 语言环境
plot 图形输出
write, write.csv, saveRDS etc 保存数据
options par 改变全局设置
S4 的相关函数 改变全局的类和方法
随机数发生器
可以使用invisibleprint的时候不显示返回值, 加上()可以强制显示
a <- 2
(a <- 2)
## [1] 2
[1] 2
on.exit()也可以跳出函数不如tryCatch

一定要注意的是要加add = TRUE不然会替代前一个调用但是默认参数为FALSE,不推荐使用

0

阅读 收藏 喜欢 打印举报/Report
后一篇:R语言tips之五
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有