R 循环

循环(loop)是R用来重复完成某个任务的方法,让我们用score函数来解决一个实际问题。

老虎机程序模拟的是现实生活中一批颇具争议的老虎机,人们认为这批老虎机有作弊嫌疑。这批老虎机的返还率看似为40美分/美元,但是制造商却声称这批机器的返还率是 92美分/美元。可以用score精确计算出这批机器的返还率,也就是老虎机中奖金额的期望值。

1、期望值

一个随机事件的期望值可以看作某种加权平均值。它是该事件每一个可能=结果乘以权值后所得结果的总和,权值对应每一个可能结果出现的概率。E(x)=(x,P(x,))

die <- c(1,2,3,4,5,6)
E= 1*1/6+2*1/6+3*1/6+4*1/6+5*1/6+6*1/6
E

R语言 循环画图jpg设置大小 r语言loop循环_数据分析


因此,掷一个均匀的骰子,其点数的期望值是3.5.这其实就是所有可能点数的平均值。

在计算这些期望值的时候,我们用了三步。

(1)列出所有可能出现的结果。
(2)决定每个可能结果对应的值(在这个例子中就是骰子的点数)
(3)计算每个可能结果出现的概率。

将第二步中的值乘以第三步中对应的概率,再加总即得到期望值。用这三个步骤可以计算出更加复杂的期望值。

比如,列出所有可能出现的结果。当你掷两个骰子时,总共有36种可能出现的点数组合。

2、expand.grid

R中expand的.grid函数可以方便快捷地写出n个向量元素的所有组合。比如说,要将两个骰子的所有点数组合都列出来,只需要将对象die的两个副本交给expand.grid即可。

rolls<-expand.grid(die,die)

R语言 循环画图jpg设置大小 r语言loop循环_大数据_02


expand.grid会返回一个含有两个骰子所有可能点数组合的数据框。

比如,你可以列出三个骰子的所有点数组合,代码为:expand.grid(die,die,die)。

expand.grid中所有元素的所有可能组合。数据框中的每一个元素都对应一个组合。

列出两个骰子的点数组合之后,便可以进一步确定每一次掷骰子的总点数了,也就是两个骰子的点数之和。可以用R的元素方式执行来计算结果。

rolls$value<-rolls$Var1+rolls$Var2
rolls

R语言 循环画图jpg设置大小 r语言loop循环_数据分析_03


n个独立随机事件同时发生的概率等于每个随机事件单独发生的概率的乘积。

P(A&B&C&…)=P(A)*P(B)*P©…

得到三个随机的形状:

get_symbols <- function(){
  whell <- c("DD","7","BBB","BB","B","C","0")
  sample(whell,size = 3,replace = TRUE,prob = c(0.03,0.03,0.06,0.1,0.25,0.01,0.52))
}

R语言 循环画图jpg设置大小 r语言loop循环_大数据_04

首先,找到var1中所有点数对应的概率值。这可以通过如下的查找表方法得到。

prob<-c("1"=1/8,"2"=1/8,"3"=1/8,"4"=1/8,"5"=1/8,"6"=3/8)
prob
rolls$Var1
prob[rolls$Var1]
rolls$prob1<-prob[rolls$Var1]
head(rolls,3)

我们可以用同样的查找表方法找到Var2中点数对应的概率值。

rolls$prob2<-prob[rolls$Var2]

通过prob1和prob2相乘得到每个点数组合的概率值。

rolls$prob<-rolls$prob1*rolls$prob2

现在已经有了每种组合及其对应的点数,以及每个点数组合对应的概率值,计算期望值就比较容易了。只需要将点数与对应的概率相乘再求和就可以得到期望值。

sum(rolls$value*rolls$prob)

使用expand.grid函数,从以下这个向量wheel中取三个符号,生成一个数据框。要求该数据框包含所有可能的符号组合。

wheel<-c("DD","7","BBB","BB","B","C","0")

在调用expand.grid函数时,设置参数stringsAsFactors=FALSE,否则expand.grid会将所有可能的组合以因子的形式存储在数据框中,score函数将无法处理这种情况。

combos<-expand.grid(wheel,wheel,wheel,stringsAsFactors=FALSE)
  combos

查找Var1中所有值对应的概率,然后将概率值作为一个新列prob1添加combos到中.对Var2和Var3执行同样的操作,以生成新列prob2和prob3。
在查找表中使用R的取值记号得到想要的值。取值结果将和你所使用的索引值一一对应。

combos$prob1 <- prob[combos$Var1]
combos$prob2 <- prob[combos$Var2]
combos$prob3 <- prob[combos$Var3]
head(combos,5)

R语言 循环画图jpg设置大小 r语言loop循环_循环_05


计算中将价格的函数:

score <- function(symbols){
  same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
  bars <- symbols %in% c("B","BB","BBB")
  if (same){
    payouts <- c("DD" = 100,"7" = 80,"BBB" = 40,"BB" = 25,"B" = 10, 
                 "C"=10,"0" = 0)
    prize <- unname(payouts[symbols[1]])
  }else if(all(bars)){
    prize <- 5
  }else{
    cherries <- sum(symbols == "C")
    prize <- c(0,2,5)[cherries + 1]
  }
  diamonds <- sum(symbols == "DD")
  prize * 2^ diamonds
}

计算每一种符号组合出现的总概率。将这些概率值存为combos的一列,并将该列命名为prob,然后进行检查。

可以通过R的元素方式执行一次性计算所有符号组合的概率。

combos$prob <- combos$prob1 * combos$prob2 * combos$prob3
head(combos)

所有可能的符号组合对应的概率值之和等于1,这意味着计算无误。

sum(combos$prob)

3、for循环

for循环可以重复运行某段代码一定的次数,重复次数取决于循环的输入中有多少个元素。用R的语法表述如下。

for(value in that){
	this
}

这里的that应该是一个对象集合(通常是一个包含数值或字符串的向量)。对于出现在that中的每一个值,for循环都会运行一遍位于两个大括号之间的代码。

for(value in c("My","first","for","loop")){
  print(value)}

R语言 循环画图jpg设置大小 r语言loop循环_R语言 循环画图jpg设置大小_06


小心选择循环符号

无论处于什么环境中,只要调用了循环语句,R就会在该环境中运行循环代码。如果循环使用了该环境中已经存在的对象名称,就会发生冲突。循环将使用它所创建的对象覆盖当前环境中已经存在的对象。对于值符号来说也是如此。

针对集合运行for 循环
在许多编程语言中,for循环是用来处理整数的,而不是处理集合。R的for循环不是针对整数序列运行,而是针对一个集合。

利用for循环计算combos的每一行对应的中奖金额
开始之前,先在combos中创建一个新列用来存储for循环的输出结果。

combos$prize <- NA
head(combos)

R语言 循环画图jpg设置大小 r语言loop循环_循环_07


上面的代码创建了一个名为prize的新列,并且暂时用缺失值符号NA填满。虽然这里只用了一个NA赋值,但是R会利用其循环规则将该列的所有位置都填上NA。

编写一个for循环,对combos的343行都运行一遍score函数。该循环应该做到,针对combos第i行的前三个元素运行score函数,并且把结果存储在combos$prize的第i个位置。

for (i in 1:nrow(combos)){
  symbols <- c(combos[i,1],combos[i,2],combos[i,3])
  combos$prize[i] <- score(symbols)
}

期望值就等于combosR语言 循环画图jpg设置大小 r语言loop循环_R_08prob.期望值也就是老虎机的返还率。

sum(combos$prize*combos$prob)

处理钻石百搭符号函数

#处理百搭钻石符号

score <- function(symbols){
  diamonds <- sum(symbols == "DD")
  cherries <- sum(symbols == "C")
  
  slots <- symbols[symbols != "DD"]
  same <- length(unique(slots)) == 1
  bars <- slots %in% c("B","BB","BBB")
  
  #分配奖金
  if (diamonds == 3){
    prize <- 100
  }else if (same){
    payouts <- c("DD" = 100,"7" = 80,"BBB" = 40,"BB" = 25,"B" = 10, 
                 "C"=10,"0" = 0)
    prize <- unname(payouts[slots[1]])
  }else if (all(bars)){
    prize <- 5
  }else if (cherries > 0){
    prize <- c(0,2,5)[cherries + diamonds + 1 ]
  }else{
    prize <- 0
  }
  #根据钻石数量奖金翻倍
  prize * 2^diamonds
}

**利用新版的score函数,再次计算老虎机的期望值。你可以使用现有的combos数据框,但是需要用for循环重新计算combos$prize列。
**

for (i in 1:nrow(combos)){
  symbols <- c(combos[i,1],combos[i,2],combos[i,3])
  combos$prize[i] <- score(symbols)
}

然后重新计算期望值。

sum(combos$prize*combos$prob)

R语言 循环画图jpg设置大小 r语言loop循环_数据分析_09

4.while循环

while(condition){
	code
 }

while会在每一次循环之前重新运行condition,这是一个逻辑测试。如果对condition求值的结果为TRUE,while就会运行大括号内的代码段;如果对condition求值的结果为FALSE,while就会结束循环。

while循环可以做的事情包括运行不定次数的迭代过程,如计算老虎机用光你所有的钱需要多久(见下面的代码)。但是,从实际应用来看,while循环在中的使用率要明显低于for循环。

play <- function(){
  symbols <- get_symbols()
  print(symbols)
  score(symbols)
}
play_till_broke <- function(start_with){
  cash <- start_with
  n <- 0
  while (cash > 0){
    cash <- cash - 1 +play()
    n <- n+1
    
  }
  n
}

play_till_broke(100)

R语言 循环画图jpg设置大小 r语言loop循环_R语言 循环画图jpg设置大小_10

5、repeat循环

repeat循环甚至比while循环还要初级。它会一直重复运行某段代码,直到你终止循环(通过按Esc键),或者是它遇到了break命令(用来强制终止程序运行的命令)。

可以用repeat循环重写上面的playstillbroke函数该函数用于计算玩老虎机需要多久用光所有的钱。

play_till_broke <- function(start_with){
  cash <- start_with
  n <- 0
  repeat{
    cash <- cash - 1 +play()
    n <- n+1
    if (cash <= 0){
      break
    }
    
  }
  n
}

play_till_broke(100)

练习:

找出自带数据集airquality中Temp值大于80的Ozone、Temp列的值。

data <- airquality
data$Temp[data["Temp"] > 80]
data$Ozone[data["Temp"] > 80]

R语言 循环画图jpg设置大小 r语言loop循环_数据分析_11