如何使用 `sample_n` 将 `dplyr` 中的数据集自动平衡到最小的 class 的大小?
How to balance a dataset in `dplyr` using `sample_n` automatically to the size of the smallest class?
我有一个像这样的数据集:
df <- tibble(
id = 1:18,
class = rep(c(rep(1,3),rep(2,2),3),3),
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
该数据集包含几个 classes 中的许多观察结果。 classes 不平衡。在上面的示例中,我们可以看到,只有 3 个观测值是 class 3,而 class 2 有 6 个观测值,class 1.
有 9 个观测值
现在我想自动平衡该数据集,以便所有 class 的大小相同。所以我想要一个 9 行的数据集,每行 3 行 class。我可以使用 dplyr
中的 sample_n
函数来进行这样的采样。
我通过首先计算最小的 class 大小来做到这一点..
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
我想知道是否可以一次性做到这一点(计算最小 class 尺寸然后采样)?
你可以一步完成,但有点作弊:
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
函数一次只能看到一组,所以我们需要 side-step 那一点。
一个人可以做到
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
虽然我不认为那是更多 elegant/readable。
我有一个像这样的数据集:
df <- tibble(
id = 1:18,
class = rep(c(rep(1,3),rep(2,2),3),3),
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
该数据集包含几个 classes 中的许多观察结果。 classes 不平衡。在上面的示例中,我们可以看到,只有 3 个观测值是 class 3,而 class 2 有 6 个观测值,class 1.
有 9 个观测值现在我想自动平衡该数据集,以便所有 class 的大小相同。所以我想要一个 9 行的数据集,每行 3 行 class。我可以使用 dplyr
中的 sample_n
函数来进行这样的采样。
我通过首先计算最小的 class 大小来做到这一点..
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
我想知道是否可以一次性做到这一点(计算最小 class 尺寸然后采样)?
你可以一步完成,但有点作弊:
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
函数一次只能看到一组,所以我们需要 side-step 那一点。
一个人可以做到
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
虽然我不认为那是更多 elegant/readable。