R语言采样循环神秘Bug:赋值方式导致sample()结果不一致
R中sample()结果不一致的原因及修复
问题重现
在R代码中遇到sample()函数结果因调用次数而非赋值方式产生差异的问题,最小可复现代码如下:
# Sampling Bug MRE rm(list = ls()) library(tidyverse) ages=c(paste0("CHILD",seq(1,10),"AGE")) set.seed(26) df=c() for(i in 1:10){ x=round(runif(1:100,min=1,max=20),0) df = as.data.frame(cbind(df,x)) } names(df)=ages set.seed(26) df$`Sampled Child`=0 test_vector=c() for(i in 1:nrow(df)){ childs_age = unlist(c(as.numeric(df[i,ages]))) slice=which(childs_age<=17) if(length(slice)>=1){ df$`Sampled Child`[i]=sample(x=slice,size=1,replace = F) test_vector=append(test_vector,sample(x=slice,size=1,replace = F)) } else{ df$`Sampled Child`[i]="Ineligibile" test_vector=append(test_vector,"Ineligibile") } } df$test=test_vector sum(df$`Sampled Child`==df$test)
运行后会发现sum(df$Sampled Child==df$test)的结果远小于100,说明两列结果不一致。
核心原因
问题的本质不是赋值方式不同,而是在同一个循环迭代中连续调用了两次sample()函数:
- R的随机数生成器是基于状态的,每次调用
sample()(或其他随机函数如runif())都会消耗当前的随机数状态,生成下一个随机结果。 - 你在给数据框列赋值时调用了一次
sample(),紧接着给向量追加元素时又调用了一次相同参数的sample(),两次调用使用的是不同的随机数状态,自然得到不同的结果。 - 额外说明:
df$Sampled Child``初始为数值型,赋值字符串时会被强制转为字符型,但这只是数据类型的小问题,不影响结果不一致的核心逻辑。
修复方法
要让两个结果一致,只需将sample()的结果先存储到一个临时变量中,再用这个变量完成两次赋值操作,避免重复调用sample():
set.seed(26) df$`Sampled Child`=0 test_vector=c() for(i in 1:nrow(df)){ childs_age = unlist(c(as.numeric(df[i,ages]))) slice=which(childs_age<=17) if(length(slice)>=1){ # 先获取一次采样结果,复用这个结果 sampled_result <- sample(x=slice, size=1, replace = FALSE) df$`Sampled Child`[i] <- sampled_result test_vector <- append(test_vector, sampled_result) } else{ df$`Sampled Child`[i] <- "Ineligibile" test_vector <- append(test_vector, "Ineligibile") } } df$test <- test_vector sum(df$`Sampled Child`==df$test) # 此时结果为100,两列完全一致
内容的提问来源于stack exchange,提问作者ssm1020
相关产品推荐
相关产品推荐

