我是R的初学者,我试图创建一个生日悖论函数,并设法达到了这一点,结果大约是0.5,正如预期的那样。
k <- 23
sims <- 1000
event <- 0
for (i in 1:sims) {
days <- sample(1:365, k, replace = TRUE)
days.unique <- unique(days)
if (length(days.unique) < k) {
event <- event + 1 }
answer <- event/sims}
answer
然而,当我试图将其放入函数中时,结果总是0.001。下面是代码:
bdayfunction<- function(k){
sims <- 1000
event <- 0
for (i in 1:sims) {
days <- sample(1:365, k, replace = TRUE)
days.unique <- unique(days)
if (length(days.unique) < k) {
event <- event + 1 }
answer <- event/sims
return (answer)
}
}
我做错了什么?
您的return
不在正确的位置:它在循环中(顺便说一下,您的answer
计算也是如此)。
如此:
bdayfunction<- function(k){
sims <- 1000
event <- 0
for (i in 1:sims) {
days <- sample(1:365, k, replace = TRUE)
days.unique <- unique(days)
if (length(days.unique) < k) {
event <- event + 1 }
}
answer <- event/sims
return (answer)
}
在R中,您可以使用允许您进行分组操作的库。两种主要的是data.table
和dplyr
。在这里,您可以尝试为所有模拟创建一个长数据帧,然后计算每个模拟的唯一天数,然后计算低于k
的发生次数,而不是执行循环。与dplyr
:
library(dplyr)
bdayfunction_dplyr <- function(k){
df <- data.frame(sim = rep(1:sims,each = k),
days = sample(1:365, k*sims, replace = TRUE))
return(
df %>%
group_by(sim) %>%
summarise(plouf = length(unique(days))< k) %>%
summarise(out = sum(plouf)/1000) %>%
pull(out)
)
}
Indata.table
:
library(data.table)
bdayfunction_data.table <- function(k){
dt <- data.table(sim = rep(1:sims,each = k),
days = sample(1:365, k*sims, replace = TRUE))
return(dt[,length(unique(days)),sim][V1<k,.N/1000])
}
您可以测试它们是否提供相同的结果:
set.seed(123)
bdayfunction(23)
[1] 0.515
set.seed(123)
bdayfunction_dplyr(23)
[1] 0.515
set.seed(123)
bdayfunction_data.table(23)
[1] 0.515
现在让我们比较一下速度:
library(microbenchmark)
microbenchmark(initial = bdayfunction(23),
dplyr = bdayfunction_dplyr(23),
data.table = bdayfunction_data.table(23))
Unit: milliseconds
expr min lq mean median uq max neval cld
initial 7.3252 7.56900 8.435564 7.7441 8.15995 24.7681 100 a
dplyr 12.3488 12.96285 16.846118 13.3777 14.71370 295.6716 100 b
data.table 5.9186 6.24115 6.540183 6.4494 6.75640 8.1466 100 a
您可以看到,data.table
比初始循环稍微快一些,而且写起来更短。