6 Control structure oin R
6.1 Introduction
- if, else: 测试逻辑条件;
- for: 执行固定次数的循环;
- while: 执行条件为真时的循环;
- repeat: 用于执行无限循环结构;
- break: 终止并结束循环;
- next: 跳过循环中的迭代;
- return: 从函数中推出;
6.2 If-Else
- if-else的不同表达方式
if(<condition>) {
## do something
} else {
## do something else
}
or
if(<condition>) {
## do something
} else if(<condition2>) {
## do something different
} else {
## do something different
}
or
if(<condition>) {
## do something
}
if(<condition2) {
## do somthing different
}
- 举例
if(x>3) {
y<-10
} else {
y<-0
}
y<-if(x>3) {
10
} else {
0
}
6.3 For loops
- for循环的不同表达方式
x<-c("a","b","c","d")
for (i in 1:4) {
print(x[i])
}
for (i in seq_along(x)) {
print(x[i])
} ## seq_along是基于x的长度生成的序列
for (letter in x) {
print(letter)
}
for (i in 1:4) print(x[i])
- for循环在矩阵的中通常需要先进行行(列)循环再进行列(行)循环
x<-matrix(1:6,2,3)
for (i in seq_len(nrow(x))) {
for (j in seq_len(ncol(x))) {
print(x[i,j])
}
}
- 当for循环中嵌套的层数大于3/4层时代码可读性可能会变得很低;
6.4 While loops
- 举例
## one condition
count<-0
while (count<10) {
print(count)
count<-count+1
}
## more than one condition
z<-5
while (z>=3 && z<=10) {
print(z)
coin<-rbinom(1,1,0.5)
if(coin==1) { ## random walk生成随机数,这里循环什么时候结束是不确定的
z<-z+1
} else {
z<-z-1
}
}
- while循环需要设置终止程序,否则会无限运行下去;
- while循环有多个条件时,系统总是从左向右检验;
6.5 Repeat, Next, Break
- repeat, break: repeat是一个无限循环结构,退出的方法是break(在某个点强制退出)。比如:当你想计算两个值何时达到无限接近,需要通过算法不断循环,直到逼近你设置的容差
x0<-1
to1<-1e-8
repeat {
x1<-computeEstimate()
## computeEstimate() is not a real function,需要事先设定
if (abs(x1-x0)<to1) {
break
} else {
x0<-x1
}
}
- next, return: next用于跳过某一段循环,return用于跳出函数,并返回一个值,但它同样可以打断循环
for (i in 1:100) {
if (i<=20) {
## Skip the first 20 interations
next
}
## Do somthing here
}
- 在命令行和交互作用来说有其他的循环函数,如apply()等一系列函数;
7 R function
7.1 First R function
- 函数举例
## 两数字相加
add2<-function(x,y) {
x+y
}
add2(3,5)
## 返回列表中大于10的数
above10<-function(x) {
use<-x>10
x[use]
}
above<-function(x,n = 10) {
use<-x>n
x[use]
}
## 求每一列均值
columnmean<-function(y, removeNA = TRUE) { ## 去除所有空值
nc<-ncol(y)
means<-numeric(nc)
for (i in 1:nc) {
means[i]<-mean(y[,i], na.rm = removeNA)
}
means
}
7.2 Functions
- 创建函数:用function()函数进行创建,以R对象的形式进行存储,可以理解为function为程序内的一级函数,由function定义的函数为嵌套函数
f<-function(<arguments>) (
## Do something intersting
)
- 参数:定义参数时通常会设置一个默认值,当该参数可以为缺失值时则不用设置
> mydata <- rnorm(100)
> sd(mydata)
[1] 0.9194398
> sd(x = mydata)
[1] 0.9194398
> sd(x = mydata, na.rm = FALSE)
[1] 0.9194398
> sd(na.rm = FALSE, x = mydata)
[1] 0.9194398
> sd(na.rm = FALSE, mydata)
[1] 0.9194398
- na.rm表示是否剔除缺失值,当为TRUE时表示保留缺失值,反之表示剔除缺失值;
- 当参数较多时,参数顺序可以调换;
- 当参数命名过长时,可以输入参数的部分,只要那个部分有唯一的匹配,R就可以进行模糊匹配;
- Lazy evaluation 惰性求值:函数不会调用所有的参数,只会调用需要的参数,当需要的参数缺失时,系统报错
> f <- function(a, b) {
+ print(a)
+ }
> f(45)
[1] 45
> f <- function(a, b) {
+ print(a)
+ print(b)
+ }
> f(45)
[1] 45
Error in print(b) : argument "b" is missing, with no default
- "…“参数:表明一些可以传递给另一个函数的参数
1.当打算拓展一个函数(对一个已经完善的函数进行小部分的更改),但又不想重新把参数复制一遍时,可以使用”…“进行省略;
2.用于generic functions 泛化函数,这种函数通常不做任何事,它的作用是根据数据类型使用合适的方法,这类函数设置时通常需要用到…参数;
3.”…“也可以用来跳过前面一些无法事先确定但必须的参数;
4.出现在”…"后的参数必须明确地给出名称,且不能进行部分匹配;
## eg1
myplot <- function(x, y, type = "l", ...) {
plot(x, y, type = type, ...)
}
## eg2
> mean
function (x, ...)
UseMethod("mean")
## eg3
> args(paste)
function (..., sep = " ", collapse = NULL, recycle0 = FALSE)
## eg4
> paste("a", "b", sep = ":")
[1] "a:b"
> paste("a","b",se = ":")
[1] "a b :" ## 此时无法对a, b进行连接
8 Scoping rules
8.1 Symbol binding
- 向量和函数同名时并不冲突,由环境决定调用对象:
> search()
[1] ".GlobalEnv" "tools:rstudio"
[3] "package:stats" "package:graphics"
[5] "package:grDevices" "package:utils"
[7] "package:datasets" "package:methods"
[9] "Autoloads" "package:base"
- 环境的定义:
1.符号或值对的集合,可以把R中所有的东西都想成成对的符号和值;
2.每一个环境都有一个父环境(parent environment),可能有多个子环境(children);
3.只有一个环境没有父环境,这个环境为空;
4.function + an environment = a closure or function closure (闭包)
8.2 Lexical scoping
- 查找自由变量:
函数定义的环境 -> 父环境 -> 全局环境 -> 空环境 -> 报错 - 作用域的意义:
R与其他语言的一个区别在于 可以在函数中定义函数,其他语言如C是无法做到的,这是定义这个函数的环境是另一个函数,而非全局环境。 - 构造函数:在函数中构造另一个函数
> make.power <- function(n) {
+ pow <- function(x) {
+ x^n
+ }
+ pow
+ }
> cube <- make.power(3) ## cube函数的环境中n=3
> square <- make.power(2) ## square函数的环境中n=2
> cube(3)
[1] 27
> square(3)
[1] 9
8.3 Lexical vs. Dynamic scoping
- 词法作用域和动态作用域区别:在f(x)中,y和g(x)均为自由变量,g(x)并非定义在f(x)中,也不是f(x)的参数。而在g(x)中y是一个自由变量。
> y <- 10
>
> f <- function(x) {
+ y <- 2
+ y^2 + g(x)
+ }
>
> g <- function(x) {
+ x*y
+ }
> f(3)
[1] 34
- 词法作用域和动态作用域共性:在全局变量中定义函数并调用函数时,定义环境(defining environment)和调用环境(calling environment)是一致的
> g <- function(x) {
+ a <- 3
+ x+a+y
+ }
> g(2)
Error in g(2) : object 'y' not found
> y <- 3
> g(2)
[1] 8
- 据说计算机编程语言的尽头是Lisp。
8.4 Application: Optimization
R中处理优化问题的一个基本思想是,你可以利用构造函数构造一个目标函数,把目标函数定义所依赖的数据及其他包含在目标函数定义的环境中,像打包一样整合起来。
eg. 构造一个负的似然函数:返回正态分布的对数似然函数
make.NegLogLik <- function(data, fixed = c(FALSE, FALSE)) {
param <- fixed
function(p) {
param[!fixed] <- p ## 这里p是想要的参数
mu <- param[1]
sigma <- param[2]
a <- -0.5*length(data)*log(2*pi*sigma^2)
b <- -0.5*sum((data-mu)^2 / (sigma^2))
-(a + b)
}
}
Maximizing a normal likelihood
> set.seed(1); normals <- rnorm(100, 1, 2)
> nLL <- make.NegLogLik(normals)
> nLL
function(p) {
param[!fixed] <- p
mu <- param[1]
sigma <- param[2]
a <- -0.5*length(data)*log(2*pi*sigma^2)
b <- -0.5*sum((data-mu)^2 / (sigma^2))
-(a + b)
}
<bytecode: 0x0000025f6f8c0a08>
<environment: 0x0000025f73acd2d0>
> ls(environment(nLL))
[1] "data" "fixed" "param"