问题描述
df <- tibble(
id = 1:18,class = rep(c(rep(1,3),rep(2,2),var_a = rep(c("a","b"),9)
)
# A tibble: 18 x 3
id cluster var_a
<int> <dbl> <chr>
1 1 1 a
2 2 1 b
3 3 1 a
4 4 2 b
5 5 2 a
6 6 3 b
7 7 1 a
8 8 1 b
9 9 1 a
10 10 2 b
11 11 2 a
12 12 3 b
13 13 1 a
14 14 1 b
15 15 1 a
16 16 2 b
17 17 2 a
18 18 3 b
该数据集包含多个类别的多个观测值。班级不平衡。在上面的样本中,我们可以看到,只有3个观测属于3类,而有2个观测属于6类,有9个属于1类观测。
现在,我想自动平衡该数据集,以使所有类的大小相同。所以我想要一个9行的数据集,每个类3行。我可以使用sample_n
中的dplyr
函数进行这种采样。
我是通过首先计算最小的班级人数来实现的。.
min_length <- as.numeric(df %>%
group_by(class) %>%
summarise(n = n()) %>%
ungroup() %>%
summarise(min = min(n)))
..然后应用sample_n
函数:
set.seed(1)
df %>% group_by(cluster) %>% sample_n(min_length)
# A tibble: 9 x 3
# Groups: cluster [3]
id cluster var_a
<int> <dbl> <chr>
1 15 1 a
2 7 1 a
3 13 1 a
4 4 2 b
5 5 2 a
6 17 2 a
7 18 3 b
8 6 3 b
9 12 3 b
我想知道是否有可能一口气做到这一点(计算最小的班级人数然后抽样)?
解决方法
您可以一步一步完成,但是有点作弊:
set.seed(42)
df %>%
group_by(class) %>%
sample_n(min(table(df$class))) %>%
ungroup()
# # A tibble: 9 x 3
# id class var_a
# <int> <dbl> <chr>
# 1 1 1 a
# 2 8 1 b
# 3 15 1 a
# 4 4 2 b
# 5 5 2 a
# 6 11 2 a
# 7 12 3 b
# 8 18 3 b
# 9 6 3 b
我之所以说“作弊”,是因为通常您不想从管道内引用df$
。但是,由于我们要寻找的对象属性是整个帧,而table
函数一次只能看到一组,因此我们需要稍微回避一下。
一个可以做
df %>%
mutate(mn = min(table(class))) %>%
group_by(class) %>%
sample_n(mn[1]) %>%
ungroup()
# # A tibble: 9 x 4
# id class var_a mn
# <int> <dbl> <chr> <int>
# 1 14 1 b 3
# 2 13 1 a 3
# 3 7 1 a 3
# 4 4 2 b 3
# 5 16 2 b 3
# 6 5 2 a 3
# 7 12 3 b 3
# 8 18 3 b 3
# 9 6 3 b 3
尽管我认为那不是更优雅/更易读的内容。