我有一些分组数据,每个项目有一行。
我想按组进行分层抽样,有两个限制:(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
我原来的逻辑是&#34; 如果项目数量等于或大于size
,则从该组中抽取size
个项目,否则只需从该组中挑选所有项目&#34 ;.另请参阅here,here和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.因此,我们需要从具有多余项目的较大组中对附加项进行采样,以实现所需的总样本大小。在这种情况下,所需的采样将是&#34; b&#34;还有两个来自&#34; a&#34;的项目。
以下是我对最低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::createDataPartition
和strata::balancedstratification
)
答案 0 :(得分:3)
我认为你的答案几乎就在那里。您只需要在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"]