R语言实现从排列表抽样420行使各列数字频率尽可能均等的方法
R语言实现三元组合的约束抽样,保证列频率尽可能均等
核心原理说明
你使用expand.grid(rep(list(1:8), 3))生成的全量三元组合共512行,原始数据中每列的1-8每个数字均匀出现64次。抽取420行时,理论最优频次为每列每个数字出现52或53次(420÷8=52.5,无法实现完全均等,这是当前抽样规模下能达到的最小波动)。
实现方案
方案1:确定性剔除法(无需额外包,可100%复现)
仅需要定向剔除92行,即可精准控制每列频次符合最优分布,完全不需要随机抽样:
library(dplyr) # 生成全量三元组合 df <- expand.grid(rep(list(1:8), 3)) # 需要剔除的行数 n_remove <- 92 df$remove_flag <- 0 # 定向剔除,优先剔除三列计数冗余最高的行 while (sum(df$remove_flag) < n_remove) { # 统计当前各列每个数字的保留量 cnt1 <- table(df$Var1[df$remove_flag == 0]) cnt2 <- table(df$Var2[df$remove_flag == 0]) cnt3 <- table(df$Var3[df$remove_flag == 0]) # 筛选待剔除的目标行 del_row <- df %>% filter(remove_flag == 0) %>% mutate( w1 = cnt1[as.character(Var1)], w2 = cnt2[as.character(Var2)], w3 = cnt3[as.character(Var3)], total_weight = w1 + w2 + w3 ) %>% arrange(desc(total_weight)) %>% slice(1) # 标记剔除 df$remove_flag[df$Var1 == del_row$Var1 & df$Var2 == del_row$Var2 & df$Var3 == del_row$Var3] <- 1 } # 提取最终结果 result_df <- df %>% filter(remove_flag == 0) %>% select(-remove_flag)
方案2:平衡抽样法(使用工具包快速实现)
如果接受极小波动,可使用sampling包的平衡抽样算法一步实现:
library(sampling) library(dplyr) df <- expand.grid(rep(list(1:8), 3)) n_sample <- 420 # 构造列平衡的辅助变量 aux_mat <- model.matrix(~ Var1 + Var2 + Var3 - 1, data = df) # 执行平衡抽样 sample_mask <- sampling::cube(aux_mat, n = n_sample, method = "srswor") # 提取结果 result_df <- df[as.logical(sample_mask), ]
结果验证
执行以下代码即可确认每列的频次分布:
# 查看三列的数字出现频次 table(result_df$Var1) table(result_df$Var2) table(result_df$Var3)
正常输出中所有数字的出现次数仅在52和53之间,为当前场景下的最均匀分布。
内容的提问来源于stack exchange,提问作者MaVe
相关产品推荐
相关产品推荐

