如何按分组完整抽取数据集子集?以team分组抽25%数据为例
按分组完整抽样拆分DataFrame
我有一个DataFrame,需要拆分为原数据量75%和25%的两部分。要求抽样时保留team分组的完整性——比如示例数据里有8个team,要随机抽取2个完整的team作为25%的子集。
我试了用dplyr的slice_sample写代码:
testdata <- df %>% group_by(team) %>% slice_sample(n = 2)
但这段代码是每个team里抽2行,完全不符合我的需求。
数据示例
team points assists 1 1 99 33 2 1 90 28 3 1 86 31 4 1 88 39 5 2 95 34 6 2 92 30 7 2 91 32 8 2 79 35 9 3 85 36 10 3 90 29 11 3 91 24 12 3 97 26 13 4 96 28 14 4 94 18 15 4 95 19 16 4 98 25 17 5 78 36 18 5 80 34 19 5 85 39 20 5 89 33 21 6 94 34 22 6 85 39 23 6 99 28 24 6 79 31 25 7 78 35 26 7 99 29 27 7 98 36 28 7 75 39 29 8 97 33 30 8 68 26 31 8 86 38 32 8 76 31
错误代码的执行结果
team points assists <dbl> <dbl> <dbl> 1 1 90 28 2 1 99 33 3 2 95 34 4 2 92 30 5 3 91 24 6 3 85 36 7 4 95 19 8 4 98 25 9 5 80 34 10 5 78 36 11 6 85 39 12 6 94 34 13 7 78 35 14 7 98 36 15 8 76 31 16 8 86 38
DataFrame结构
structure(list(team = c(1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8), points = c(99, 90, 86, 88, 95, 92, 91, 79, 85, 90, 91, 97, 96, 94, 95, 98, 78, 80, 85, 89, 94, 85, 99, 79, 78, 99, 98, 75, 97, 68, 86, 76), assists = c(33, 28, 31, 39, 34, 30, 32, 35, 36, 29, 24, 26, 28, 18, 19, 25, 36, 34, 39, 33, 34, 39, 28, 31, 35, 29, 36, 39, 33, 26, 38, 31)), class = "data.frame", row.names = c(NA, -32L))
解决方案
要实现按完整分组抽样,核心思路是先随机抽取分组(team),再根据选中的分组筛选原数据。
方法1:分步实现
library(dplyr) # 提取所有唯一team,随机抽取2个 selected_teams <- df %>% distinct(team) %>% slice_sample(n = 2) # 筛选选中team的全部数据作为25%子集 subset_25 <- df %>% filter(team %in% selected_teams$team) # 剩余数据为75%主数据集 subset_75 <- df %>% filter(!team %in% selected_teams$team)
方法2:链式简洁写法
# 一步生成25%子集 subset_25 <- df %>% inner_join( df %>% distinct(team) %>% slice_sample(n = 2), by = "team" ) # 生成75%子集 subset_75 <- anti_join(df, subset_25, by = "team")
逻辑解释
distinct(team):提取所有不重复的分组标识,这里是8个teamslice_sample(n = 2):从分组列表中随机抽取2个,保证分组完整性- 用
filter或inner_join/anti_join筛选对应分组的全部数据,最终子集的总数据量刚好是原数据的25%(每个team4行,2个team共8行,占32行的25%)
内容的提问来源于stack exchange,提问作者Beardedant
相关产品推荐
相关产品推荐

