load("/Users/xrb/Desktop/R语言学习/R Programming/Hands-On Programming with R/R Programming Learning/slot_machine.RData") #调用老虎机的工作环境
{# load("/Users/xrb/Desktop/R语言学习/R Programming/Hands-On Programming with R/R Programming Learning/slot_machine.RData") #调用老虎机的工作环境}
循环是 R 重复任务的方法,这使得它们成为编程模拟的有用工具。本章将教你如何使用R的循环工具。
让我们使用该score函数来解决实际问题。
您的老虎机是根据被指控欺诈的真实机器建模的。这些机器似乎每 1 美元支付
40 美分,但制造商声称他们每 1 美元支付 92
美分。您可以使用该score程序计算机器的准确支付率。支付率将是老虎机奖金的预期值
\(E(x)=n∑i=1(xi⋅P(xi))\)
随机事件的期望值是一种加权平均值;它是事件的每个可能结果的总和,并按每个结果发生的概率进行加权.
对于计算两个骰子和的概率问题时,我们可以把步骤进行如下拆解:
列出所有可能的结果
确定每个结果的价值(这里只是骰子的价值)
计算每个结果发生的概率
当您掷两个骰子时,总共会出现 36 种不同的结果,列出这些组合可能很乏味,但 R 有一个函数可以提供帮助。
R 中的函数expand.grid提供了一种快速写出n
个向量中元素的每种组合的方法。例如,您可以列出两个骰子的每种组合。为此,请运行expand.grid以下两个副本die:
## Var1 Var2
## 1 1 1
## 2 2 1
## 3 3 1
## 4 4 1
## 5 5 1
## 6 6 1
## 7 1 2
## 8 2 2
## 9 3 2
## 10 4 2
## 11 5 2
## 12 6 2
## 13 1 3
## 14 2 3
## 15 3 3
## 16 4 3
## 17 5 3
## 18 6 3
## 19 1 4
## 20 2 4
## 21 3 4
## 22 4 4
## 23 5 4
## 24 6 4
## 25 1 5
## 26 2 5
## 27 3 5
## 28 4 5
## 29 5 5
## 30 6 5
## 31 1 6
## 32 2 6
## 33 3 6
## 34 4 6
## 35 5 6
## 36 6 6
计算出每次投掷一对骰子的点数和,添加到组合数据框中:
## Var1 Var2 value
## 1 1 1 2
## 2 2 1 3
## 3 3 1 4
## 4 4 1 5
## 5 5 1 6
## 6 6 1 7
## 7 1 2 3
## 8 2 2 4
## 9 3 2 5
## 10 4 2 6
## 11 5 2 7
## 12 6 2 8
## 13 1 3 4
## 14 2 3 5
## 15 3 3 6
## 16 4 3 7
## 17 5 3 8
## 18 6 3 9
## 19 1 4 5
## 20 2 4 6
## 21 3 4 7
## 22 4 4 8
## 23 5 4 9
## 24 6 4 10
## 25 1 5 6
## 26 2 5 7
## 27 3 5 8
## 28 4 5 9
## 29 5 5 10
## 30 6 5 11
## 31 1 6 7
## 32 2 6 8
## 33 3 6 9
## 34 4 6 10
## 35 5 6 11
## 36 6 6 12
接下来,计算独立事件同时发生的概率:
\(P(A&B&C&...)=P(A)⋅P(B)⋅P(C)⋅...\)
一个不均匀的骰子1到6各点数数显的概率分别为:1/8,1/8,1/8,1/8,1/8,3/8
首先,可以使用lookup table 将第一个骰子的点数和概率做一个对应:
## 1 2 3 4 5 6
## 0.125 0.125 0.125 0.125 0.125 0.375
然后在数据框rolls中生成一个变量来记录第一个骰子的点数概率:
## Var1 Var2 value prob1
## 1 1 1 2 0.125
## 2 2 1 3 0.125
## 3 3 1 4 0.125
## 4 4 1 5 0.125
## 5 5 1 6 0.125
## 6 6 1 7 0.375
## 7 1 2 3 0.125
## 8 2 2 4 0.125
## 9 3 2 5 0.125
## 10 4 2 6 0.125
## 11 5 2 7 0.125
## 12 6 2 8 0.375
## 13 1 3 4 0.125
## 14 2 3 5 0.125
## 15 3 3 6 0.125
## 16 4 3 7 0.125
## 17 5 3 8 0.125
## 18 6 3 9 0.375
## 19 1 4 5 0.125
## 20 2 4 6 0.125
## 21 3 4 7 0.125
## 22 4 4 8 0.125
## 23 5 4 9 0.125
## 24 6 4 10 0.375
## 25 1 5 6 0.125
## 26 2 5 7 0.125
## 27 3 5 8 0.125
## 28 4 5 9 0.125
## 29 5 5 10 0.125
## 30 6 5 11 0.375
## 31 1 6 7 0.125
## 32 2 6 8 0.125
## 33 3 6 9 0.125
## 34 4 6 10 0.125
## 35 5 6 11 0.125
## 36 6 6 12 0.375
第二个骰子概率同理:
## Var1 Var2 value prob1 prob2
## 1 1 1 2 0.125 0.125
## 2 2 1 3 0.125 0.125
## 3 3 1 4 0.125 0.125
## 4 4 1 5 0.125 0.125
## 5 5 1 6 0.125 0.125
## 6 6 1 7 0.375 0.125
## 7 1 2 3 0.125 0.125
## 8 2 2 4 0.125 0.125
## 9 3 2 5 0.125 0.125
## 10 4 2 6 0.125 0.125
## 11 5 2 7 0.125 0.125
## 12 6 2 8 0.375 0.125
## 13 1 3 4 0.125 0.125
## 14 2 3 5 0.125 0.125
## 15 3 3 6 0.125 0.125
## 16 4 3 7 0.125 0.125
## 17 5 3 8 0.125 0.125
## 18 6 3 9 0.375 0.125
## 19 1 4 5 0.125 0.125
## 20 2 4 6 0.125 0.125
## 21 3 4 7 0.125 0.125
## 22 4 4 8 0.125 0.125
## 23 5 4 9 0.125 0.125
## 24 6 4 10 0.375 0.125
## 25 1 5 6 0.125 0.125
## 26 2 5 7 0.125 0.125
## 27 3 5 8 0.125 0.125
## 28 4 5 9 0.125 0.125
## 29 5 5 10 0.125 0.125
## 30 6 5 11 0.375 0.125
## 31 1 6 7 0.125 0.375
## 32 2 6 8 0.125 0.375
## 33 3 6 9 0.125 0.375
## 34 4 6 10 0.125 0.375
## 35 5 6 11 0.125 0.375
## 36 6 6 12 0.375 0.375
计算点数和所对应的概率:
## Var1 Var2 value prob1 prob2 prob
## 1 1 1 2 0.125 0.125 0.015625
## 2 2 1 3 0.125 0.125 0.015625
## 3 3 1 4 0.125 0.125 0.015625
## 4 4 1 5 0.125 0.125 0.015625
## 5 5 1 6 0.125 0.125 0.015625
## 6 6 1 7 0.375 0.125 0.046875
## 7 1 2 3 0.125 0.125 0.015625
## 8 2 2 4 0.125 0.125 0.015625
## 9 3 2 5 0.125 0.125 0.015625
## 10 4 2 6 0.125 0.125 0.015625
## 11 5 2 7 0.125 0.125 0.015625
## 12 6 2 8 0.375 0.125 0.046875
## 13 1 3 4 0.125 0.125 0.015625
## 14 2 3 5 0.125 0.125 0.015625
## 15 3 3 6 0.125 0.125 0.015625
## 16 4 3 7 0.125 0.125 0.015625
## 17 5 3 8 0.125 0.125 0.015625
## 18 6 3 9 0.375 0.125 0.046875
## 19 1 4 5 0.125 0.125 0.015625
## 20 2 4 6 0.125 0.125 0.015625
## 21 3 4 7 0.125 0.125 0.015625
## 22 4 4 8 0.125 0.125 0.015625
## 23 5 4 9 0.125 0.125 0.015625
## 24 6 4 10 0.375 0.125 0.046875
## 25 1 5 6 0.125 0.125 0.015625
## 26 2 5 7 0.125 0.125 0.015625
## 27 3 5 8 0.125 0.125 0.015625
## 28 4 5 9 0.125 0.125 0.015625
## 29 5 5 10 0.125 0.125 0.015625
## 30 6 5 11 0.375 0.125 0.046875
## 31 1 6 7 0.125 0.375 0.046875
## 32 2 6 8 0.125 0.375 0.046875
## 33 3 6 9 0.125 0.375 0.046875
## 34 4 6 10 0.125 0.375 0.046875
## 35 5 6 11 0.125 0.375 0.046875
## 36 6 6 12 0.375 0.375 0.140625
现在我们可以计算出一对不均匀骰子和的期望值了:
## [1] 8.25
让我们使用我们的方法来计算老虎机奖金的预期值。我们将遵循刚刚采取的相同步骤:
我们将列出玩这台机器的每一种可能的结果。这将是三个老虎机符号的每种组合的列表。
当你玩机器时,我们会计算得到每种组合的概率。
我们将确定每个组合将赢得的奖品。
## [1] "DD" "7" "BBB" "BB" "B" "C" "0"
## Var1 Var2 Var3
## 1 DD DD DD
## 2 7 DD DD
## 3 BBB DD DD
## 4 BB DD DD
## 5 B DD DD
## 6 C DD DD
prob0 = c("DD"=0.03, "7"=0.03, "BBB"=0.06,"BB"= 0.1,"B"= 0.25, "C"=0.01, "0"=0.52) #生成查找表
symbol2$prob1 = prob0[symbol2$Var1] #第一个形状的概率
symbol2$prob2 = prob0[symbol2$Var2] #第二个
symbol2$prob3 = prob0[symbol2$Var3] #第三个
symbol2$prob = symbol2$prob1*symbol2$prob2*symbol2$prob3 #总概率
head(symbol2)## Var1 Var2 Var3 prob1 prob2 prob3 prob
## 1 DD DD DD 0.03 0.03 0.03 0.000027
## 2 7 DD DD 0.03 0.03 0.03 0.000027
## 3 BBB DD DD 0.06 0.03 0.03 0.000054
## 4 BB DD DD 0.10 0.03 0.03 0.000090
## 5 B DD DD 0.25 0.03 0.03 0.000225
## 6 C DD DD 0.01 0.03 0.03 0.000009
#奖金匹配函数
score <- function(symbols) {
# identify case
same <- symbols[1] == symbols[2] && symbols[2] == symbols[3]
bars <- symbols %in% c("B", "BB", "BBB")
# get prize
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] #上方的if树可以用查找table的形式实现
}
# adjust for diamonds
diamonds = sum(symbols == "DD")
prize = prize*2^diamonds
prize
}
#获得每个形状组合的对应奖金:
symbols <- c(symbol2[1, 1], symbol2[1, 2], symbol2[1, 3])
score(symbols) #获得了第一行形状组合的奖金## [1] 800
可以使用for循环完成。
for循环多次重复代码块,一组输入中的每个元素重复一次。在 R 语法中,这看起来像:
for (value in that) {
this
}
例子:
## [1] "one run"
## [1] "one run"
## [1] "one run"
## [1] "one run"
for 循环中的符号value就像函数中的参数一样。for
循环将创建一个名为
的对象value,并在每次运行循环时为其分配一个新值。循环中的代码可以通过调用该value对象来访问该值。
例子:
## [1] "My"
## [1] "second"
## [1] "for"
## [1] "loop"
你可以在for循环中使用任何你喜欢的参数符号来做同样的事情,只要该符号出现在for后面的括号中。
例子:
## [1] "My"
## [1] "second"
## [1] "for"
## [1] "loop"
## [1] "My"
## [1] "second"
## [1] "for"
## [1] "loop"
保存循环结果:
要保存for循环的输出结果,您必须编写循环,以便它在运行时保存自己的输出。您可以通过在运行for循环之前创建一个空向量或列表来完成此操作。然后使用for循环来填充向量或列表。循环完成后,您将能够访问向量或列表,其中现在包含您的所有结果。
例子:
chars = vector(length = 4) #构建一个空向量
#构建一个循环来填充此向量
words = c("My","fourth", "for", "loop")
for (i in 1:4) {
chars[i] = words[i]
}
chars## [1] "My" "fourth" "for" "loop"
在实践中,您会发现for循环并不是用来运行代码,而是用代码结果填充向量和列表。
现在,让我们使用for循环来填充每一行奖金:
symbol2$prize = NA #新建一个空的变量
for (i in 1:nrow(symbol2)) {
symbols <- c(symbol2[i, 1], symbol2[i, 2], symbol2[i, 3])
symbol2$prize[i] = score(symbols)
}
head(symbol2) #成功对应## Var1 Var2 Var3 prob1 prob2 prob3 prob prize
## 1 DD DD DD 0.03 0.03 0.03 0.000027 800
## 2 7 DD DD 0.03 0.03 0.03 0.000027 0
## 3 BBB DD DD 0.06 0.03 0.03 0.000054 0
## 4 BB DD DD 0.10 0.03 0.03 0.000090 0
## 5 B DD DD 0.25 0.03 0.03 0.000225 0
## 6 C DD DD 0.01 0.03 0.03 0.000009 8
计算老虎机奖金期望:
## [1] 0.538014
调整score函数让钻石DD充当百搭的作用:
score <- function(symbols) {
diamonds <- sum(symbols == "DD")
cherries <- sum(symbols == "C")
# identify case
# since diamonds are wild, only nondiamonds
# matter for three of a kind and all bars
slots <- symbols[symbols != "DD"]
same <- length(unique(slots)) == 1
bars <- slots %in% c("B", "BB", "BBB")
# assign prize
if (diamonds == 3) {
prize <- 100
} else if (same) {
payouts <- c("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) {
# diamonds count as cherries
# so long as there is one real cherry
prize <- c(0, 2, 5)[cherries + diamonds + 1]
} else {
prize <- 0
}
# double for each diamond
prize * 2^diamonds
}
symbol2$prize = NA #新建一个空的变量
for (i in 1:nrow(symbol2)) {
symbols <- c(symbol2[i, 1], symbol2[i, 2], symbol2[i, 3])
symbol2$prize[i] = score(symbols)
}
symbol2 #成功对应
对于for循环,R有两个同伴:while循环和repeat循环。while循环在某个条件保持为TRUE时重新运行块。要创建while循环,请在while后面加上一个条件和一块代码,如下所示:
如果condition计算结果为TRUE,while将运行大括号之间的代码。如果condition计算结果为FALSE,while将结束循环。
您可以使用while循环来执行需要不同迭代次数的操作,例如计算玩老虎机需要多长时间才能破产(如下所示)。然而,在实践中,while循环比R
中的for循环要少得多:
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(10)
重复循环甚至比while循环更基本。他们将重复一段代码,直到你告诉他们停止(点击Escape),或者直到他们遇到命令break,这将停止循环。
你可以使用重复循环来重新创建plays_till_broke,这是我的函数,模拟玩老虎机时赔钱的时间:
plays_till_broke <- function(start_with) {
cash <- start_with
n <- 0
repeat {
cash <- cash - 1 + play()
n <- n + 1
if (cash <= 0) {
break
}
}
n
}
plays_till_broke(5)
## 237
不幸的是,R中的循环有时可能比其他语言中的循环慢。结果,R的循环受到了不好的评价。这一声誉并非完全应得,但它确实突出了一个重要问题。速度对数据分析至关重要。当你的代码运行得很快时,你可以使用更大的数据,并在时间或计算能力耗尽之前对其做更多的处理。Speed将教你如何用R快速编写循环和一般快速代码。在那里,你将学会编写矢量化代码vectorized code,这是一种利用R所有优势的闪电般快速的代码风格。