有限制的分层抽样:固定的总规模在各组之间平均分配
Stratified sampling with restrictions: fixed total size evenly partitioned among groups
我有一些分组数据,每行一行。
我想按组进行分层抽样,有两个限制:(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
个项目,否则只选择组中的所有项目”。另见 here, here and here.
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:我考虑过比例分配(proportionate sampling),但是
当组大小的分布充分偏斜时,这种抽样显然不尊重绝对总样本大小,并且不会在组之间均匀分配样本(例如 caret::createDataPartition
和 strata::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"]
我有一些分组数据,每行一行。
我想按组进行分层抽样,有两个限制:(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
个项目,否则只选择组中的所有项目”。另见 here, here and here.
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:我考虑过比例分配(proportionate sampling),但是
当组大小的分布充分偏斜时,这种抽样显然不尊重绝对总样本大小,并且不会在组之间均匀分配样本(例如 caret::createDataPartition
和 strata::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"]