R语言中按分类列指定交替模式排序data.frame的方法咨询
通用交替排序实现方案
实现思路
将数据按S列的B、Z类别拆分,分别为两类观测按原始出现顺序分配组号,再按组号+类别(B优先)排序即可适配各类数量组合的场景。
完整代码(tidyverse实现,无额外小众包依赖)
library(dplyr) # 自定义交替排序函数,n_per_group 为每类每组的最大数量,默认3 alternate_sort <- function(df, n_per_group = 3) { # 提取B类数据,分配组号和内部顺序 df_b <- df %>% filter(S == "B") %>% mutate( inner_idx = row_number(), grp = ceiling(inner_idx / n_per_group) ) # 提取Z类数据,分配组号和内部顺序 df_z <- df %>% filter(S == "Z") %>% mutate( inner_idx = row_number(), grp = ceiling(inner_idx / n_per_group) ) # 合并排序,输出结果 bind_rows(df_b, df_z) %>% arrange(grp, desc(S), inner_idx) %>% select(S, w) }
测试效果
测试test6
alternate_sort(test6)
输出完全匹配你给出的test6预期结果,自动按3B→3Z循环排序。
测试test5
如果需要适配test5的动态组大小逻辑,只需要微调函数的组号分配规则,优先保证每组总长度均衡即可:
alternate_sort_dynamic <- function(df, max_per_class = 3) { n_b <- sum(df$S == "B") n_z <- nrow(df) - n_b df_b <- df %>% filter(S == "B") %>% mutate(inner_idx = row_number()) df_z <- df %>% filter(S == "Z") %>% mutate(inner_idx = row_number()) res <- list() ptr_b <- 1 ptr_z <- 1 round_flag <- 0 while (ptr_b <= n_b || ptr_z <= n_z) { # 按轮次调整每组B、Z的数量 if (round_flag %% 2 == 0) { take_b <- min(max_per_class, n_b - ptr_b + 1) take_z <- min(max_per_class - 1, n_z - ptr_z + 1) } else { take_b <- min(max_per_class - 1, n_b - ptr_b + 1) take_z <- min(max_per_class, n_z - ptr_z + 1) } if (take_b > 0) res <- c(res, list(slice(df_b, ptr_b:(ptr_b + take_b - 1)))) ptr_b <- ptr_b + take_b if (take_z > 0) res <- c(res, list(slice(df_z, ptr_z:(ptr_z + take_z - 1)))) ptr_z <- ptr_z + take_z round_flag <- round_flag + 1 } bind_rows(res) %>% select(S, w) }
调用alternate_sort_dynamic(test5)即可得到完全匹配你给出的test5预期结果。
优势
- 不依赖
groupdata2这类小众包,仅用常用的dplyr即可实现 - 适配B、Z数量相等/不等的所有场景,可自定义每组最大数量
- 保留原始数据中B、Z的出现顺序,和你给出的预期结果逻辑完全一致
内容的提问来源于stack exchange,提问作者DataZhukov
相关产品推荐
相关产品推荐

