星期五, 三月 16, 2012

R语言编程入门之六:循环与条件

循环
for (n in x) {expr}
R中最基本的是for循环,其中n为循环变量,x通常是一个序列。n在每次循环时从x中顺序取值,代入到后面的expr语句中进行运算。下面的例子即是以for循环计算30个Fibonacci数。
x <- c(1,1)
for (i in 3:30) {
    x[i] <- x[i-1]+x[i-2]
}

while (condition) {expr}
当不能确定循环次数时,我们需要用while循环语句。在condition条件为真时,执行大括号内的expr语句。下面即是以while循环来计算30个Fibonacci数。
x <- c(1,1)
i <- 3
while (i <= 30) {
    x[i] <- x[i-1]+x[i-2]
    i <- i +1
}



条件
if (conditon) {expr1} else {expr2}
if语句用来进行条件控制,以执行不同的语句。若condition条件为真,则执行expr1,否则执行expr2。ifesle()函数也能以简洁的方式构成条件语句。下面的一个简单的例子是要找出100以内的质数。
x <- 1:100
y <- rep(T,100)
for (i in 3:100) {
    if (all(i%%(2:(i-1))!=0)){
        y[i] <- TRUE
        } else {y[i] <- FALSE
                }
}
print(x[y])

在上面例子里,all()函数的作用是判断一个逻辑序列是否全为真,%%的作用是返回余数。在if/else语句中一个容易出现的错误就是else没有放在}的后面,若你执行下面的示例就会出现错误。
logic = 3
x<- c(2,3)
if (logic == 2){
    y <- x^2
}
else {
  y<-x^3
}
show(y)

一个例子
本例来自于"introduction to Scientific Programming and Simulatoin Using R"一书的习题。有这样一种赌博游戏,赌客首先将两个骰子随机抛掷第一次,如果点数和出现7或11,则赢得游戏,游戏结束。如果没有出现7或11,赌客继续抛掷,如果点数与第一次扔的点数一样,则赢得游戏,游戏结束,如果点数为7或11则输掉游戏,游戏结束。如果出现其它情况,则继续抛掷,直到赢或者输。用R编程来计算赌客赢的概率,以决定是否应该参加这个游戏。

craps <- function() {
    #returns TRUE if you win, FALSE otherwise
    initial.roll <- sum(sample(1:6,2,replace=T))
    if (initial.roll == 7 || initial.roll == 11) return(TRUE)
    while (TRUE) {
        current.roll <- sum(sample(1:6,2,replace=T))
        if (current.roll == 7 || current.roll == 11) {
            return(FALSE)
        } else if (current.roll == initial.roll) {
            return(TRUE)
        }
    }
}
mean(replicate(10000, craps()))

从最终结果来看,赌客赢的概率为0.46,长期来看只会往外掏钱,显然不应该参加这个游戏了。最后要说的是,本题也可以用递归来做。

5 条评论:

  1. 你好,相信你说的例子是这本书第60页的习题,但是我认为你的程序上有问题。
    if (initial.roll == 7 || initial.roll == 11) return的值应该是FALSE,因为你想要结束并推出循环。

    回复删除
    回复
    1. 在一个循环里头,出现return,就会立刻退出循环,这个目的是达到了,另外,返回TRUE是因为赢得了游戏。

      删除
  2. if (current.roll == 7 || current.roll == 11) {
    return(FALSE)
    } else if (current.roll == initial.roll) {
    return(TRUE)
    }

    第一个if条件为真应该返回TRUE,如果点数出现7或11,则赢得游戏。

    回复删除
  3. 想问问,如果想要读取一组文件名带有数字的一组数据,如何批量的读取呢?在使用read.table命令中的时候,带引号的数据是不能直接使用循环变量的。

    回复删除