如果一组中的行数超过 X 个观察值,则随机抽取 X 个行数

If the number of rows in a group exceeds X number of observations, randomly sample X number of rows

我需要减少数据集中的行数。为此,我的策略是让一组中的行数超过 X 个观察值,如果一组中的行数超过 X 行,则从每个组中随机抽取 X 行数。

假设以下数据集:

set.seed(123)
n <- 10

df <- data.frame(id = c(1:n),
                 group = sample(1:3, n, replace = T))

> df
   id group
1   1     3
2   2     3
3   3     3
4   4     2
5   5     3
6   6     2
7   7     2
8   8     2
9   9     3
10 10     1

其中 X == 2。让我们数一数每组中的行数。

> table(df$group)

1 2 3 
1 4 5 

这意味着在最终结果中,我希望在第 1 组中有 1 个观察值,在第 2 组和第 3 组中有 2 个观察值。保留在第 2 组和第 3 组中的行应该随机选择。这会将数据的大小从 10 行减少到 5 行。

如何高效地执行此操作?

谢谢!

这是一种按列分组并在slice中创建条件以检查行数(n())是否大于'X'的方法,对序列进行采样具有 X 或 return row_number() 的行 (row_number()) 的行数(或示例,以防 X 是不同的值

library(dplyr)
X <- 2
df %>% 
  group_by(group) %>% 
  slice(if(n() >= X) sample(row_number(), X, replace = FALSE) else 
     sample(row_number())) %>%
  ungroup

-输出

# A tibble: 5 × 2
     id group
  <int> <int>
1    10     1
2     8     2
3     4     2
4     1     3
5     9     3

我正在使用 data.table 添加一个似乎有效的替代方法。很高兴有替代品。

library(data.table)

X <- 2

setkey(df, "id") 

df[
  df[,
     if(.N >= X)
       .I[sample(.N, X, replace = FALSE)]
     else
       .I[sample(.N, replace = FALSE)], 
     by = group
  ]$V1
]

这导致了这个结果。

   id group
1:  5     3
2:  2     3
3:  6     2
4:  4     2
5: 10     1

当我们按组随机sample行时,可能我们可以使用pmin

df %>%
    group_by(group) %>%
    slice(sample(n(), pmin(n(), 2))) %>%
    ungroup()

及以下是 data.table 等价物

setDT(df)[, .SD[sample(.N, pmin(.N, X))], group]