一次有趣的尝试。主要讲解本期推文中使用的函数以及循环。最近在学循环,然后思考了一下马爸爸关于集五福的问题,并做了一次有趣的尝试。不知道大家还有没有印象,第一次集五福活动特别难集齐;而大家反应后,五福的概率肯定做了调整。两种情况,1)敬业福与其他福字出现概率相等时,可能只需要10张卡左右就可以集齐五福;2)敬业福出现变成极端小概率时,可能需要千张万张卡才能集齐。。。关于集五福的问题,是我在思考抛硬币概率问题后,无聊想了下便进行了有关五福收集的程序编写。今天用图简单介绍下所用的循环,主要是代码的讲解~ 
#### 集五福 #### ## 老马手里有爱国、和谐、富强、友善、敬业五种卡。 ## 假设每张卡上出现以上五种卡的可能性相同,并且可以无限次收集(放回)。 ## 集齐五福卡需要收集的卡片数?
rm(list = ls())#清空当前环境
## 定义一个函数来判断向量中独有种类的数量 count_unique <- function(x) { #自定义函数,{} 中括号中的为函数体 library(tidyverse) #加载该包是为了运行%>%管道符号 x %>% #%>% 该符号的理解可以解读成然后 #也就是这里的解读为输入x向量,然后进行下一步 unique() %>% #unique() 主要判断x向量中不同种类的唯一数量 length() #向量长度 }
## 设置种子数 set.seed(1111) #由于代码中存在随机生成的结果,设置种子目的是保证每次输出结果一致。
## 求抽取5种卡的卡片数(即求迭代次数) times <- 0 #初始数值 #while循环常用来计算迭代次数和一些数值的计算 while(times >= 0){ #while() 括号中的为条件,当满足这个条件时,进行{}中括号的内容 times = times + 1 #第二行是我们要求得次数 每次当n大于等于0时,则times+1 #这也意味着如果没有满足后面if的条件,times会一直循环下去,直到满足条件输出结果 df = sample(c("爱国","友善","富强","和谐","敬业"), times, replace = T) #sample随机抽样函数/n抽样次数/replace有放回的抽样 没有设置pro表示默认抽取情况的概率相等 if(count_unique(df)==5){ #在while循环中套用if条件的循环 #我们利用上面定义的函数,来判断是否满足我们的条件 #条件解读为:当五福均至少抽取一次,也就是自定义函数count_unique()为5时, #执行中括号中的函数体 print(times) #输出迭代次数,也就是需要的卡片数 break() #当满足if条件时,break作出停止循环的命令 } } ## 其实我们可以看出来当概率相等的时候,可能10张以内咱们就能集齐(可以更换种子数去验证结果)
## 当卡片概率不等的时候,敬业福概率只有亿分之一时,看看什么叫绝望 times <- 0 while(times >= 0){ times = times + 1 df = sample(c("爱国","友善","富强","和谐","敬业"), times, replace = T, prob = c(0.3,0.2,0.2,0.299999999,0.000000001)) if(count_unique(df)==5){ print(times) break } }
## 经过师兄最后的建议,可以用自定义函数来打包循环,可以做到重复使用 count_times <- function(x){ times <- 0 while(times >= 0){ times = times + 1 df = sample(x, times, replace = T) #抽样的向量可以自行设置 if(count_unique(df)==5){ print(times) break } } }
## 这里我们用五福和5个字母来验证一下 x <- c("爱国","友善","富强","和谐","敬业") y <- c("A","B","C","D","E") set.seed(1111) count_times(x) set.seed(1111) count_times(y) #结果相同,验证无误 用R markdown输出结果: 

 这里特别感谢我的师兄!编写命令过程中,我在判断语句部分遇到了问题,与师兄讨论后,师兄提出建议并指导我完善程序命令,解决了我的问题。快乐无穷~
|