r语言 - 有限制的分层抽样:固定的总大小在组之间均匀分配



我有一些分组数据,每个项目一行。我想按组进行分层抽样,有两个限制:(1)一定的总样本量;(2)样本应在各组之间尽可能均匀地分配(即组样本量的最小sd)。

理想情况下,我们从每个组中选择相同(固定)数量的项目,当组大小>=所有组所需的size时,这没有问题。但是,有时团体规模小于size。但是,项目总数始终高于总样本量。例如,如果总样本量为 12,有四个不同的组,我们理想情况下希望从每个组中选择 3 个项目

size_tot <- 12
n_grp <- 4
size <- size_tot / n_grp

一些数据:

d2 <- data.table(id = 1:16,
                 grp = rep(c("a", "b", "c", "d"), c(9, 4, 2, 1)))
d2
#     id grp
#  1:  1   a
#  2:  2   a
#  3:  3   a
#  4:  4   a
#  5:  5   a
#  6:  6   a
#  7:  7   a
#  8:  8   a
#  9:  9   a
# 10: 10   b
# 11: 11   b
# 12: 12   b
# 13: 13   b
# 14: 14   c
# 15: 15   c
# 16: 16   d

我最初的逻辑是"如果项目数等于或大于size,则从组中抽取size项目,否则只需从组中选择所有项目"。另请参阅此处,此处和此处。

set.seed(1)
d2[ , if(.N >= size) .SD[sample(x = .N, size = size)] else .SD, by = "grp"]
#    grp id
# 1:   a  3
# 2:   a  9
# 3:   a  5
# 4:   b 13
# 5:   b 10
# 6:   b 11
# 7:   c 14
# 8:   c 15
# 9:   d 16

在项目数量足够(a和b)的两组中,我们从各抽样3个项目。在小组(c和d)中,我们只是选择了所有的东西,即分别是2和1。这导致总样本数量为 9,即小于所需的总样本数量 12。因此,我们需要从具有剩余项目的较大组中抽取其他项目,以实现所需的总样本量。在这种情况下,所需的抽样将是"b"中的1个附加项目和"a"中的两个附加项目。

以下是我对sd最低分区的看法。总样本量可以分为四组,如下所示:

library(partitions)
cmp <- compositions(n = size_tot, m = 4)

然后可以将分区从低sd(组之间的样本大小相等 - 所需)到高sd排序:

std <- apply(cmp, 2, sd)
cmp2 <- cmp[ , order(std)]
cmp2[ , 1:10]
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,]    3    4    3    3    4    3    4    2    3     2
# [2,]    3    3    4    3    3    4    2    4    2     3
# [3,]    3    3    3    4    2    2    3    3    4     4
# [4,]    3    2    2    2    3    3    3    3    3     3

和团体规模:

d1[ , .(n = .N), by = "grp"]
#    grp n
# 1:   a 9
# 2:   b 4
# 3:   c 2
# 4:   d 1

但是如何将这个分区(总和为 12)与组样本量(不一定总和为 12)相匹配?还有人在这里闻到XY问题吗?因此,是否有我忽略的替代方法?


PS:我考虑过比例分配(比例抽样),但是当组大小的分布充分偏斜时,这种抽样显然不尊重绝对总样本量,并且不会在组间均匀分布样本(例如 caret::createDataPartitionstrata::balancedstratification

我想

你的答案差不多了。只需对 cmp2 进行筛选,即可获得满足采样大小小于或等于组大小条件的第一个采样集:

#Create a set of indices of sampling sizes that fit the criteria
original_groups <- d2[, .N, by = grp][,N]
valid_indexes <- apply(cmp2, 2, function(x) all(x <= original_groups))
#Take the first of these valid indices (lowest variance)
sampling_sizes <- cmp2[,which(valid_indexes)[1]]
#Create a sampling size variable on the datatable
d2[, sampling_size := rep(sampling_sizes, original_groups)]
#Sample as before
d2[ , .SD[sample(x = .N, size = sampling_size)], by = "grp"]

最新更新