以下是四种不同的方法。两个使用函数分别来自splitstackshape
andsampling
包,一个使用 base mapply
,一个使用map2
来自purrr
包(tidyverse
包集合的一部分)。
首先让我们设置一些假数据和采样参数:
# Fake data
set.seed(156)
df = data.frame(age=sample(0:100, 1e6, replace=TRUE))
# Add a grouping variable for age range
df = df$age.groups = cut(df$age, c(0,30,51,70,Inf), right=FALSE)
# Total number of people sampled
n = 1000
# Named vector of sample proportions by group
probs = setNames(c(0.3, 0.3, 0.2, 0.2), levels(df$age.groups))
使用上述采样参数,我们希望从每个年龄组中n
按比例对总值进行采样。probs
选项1:mapply
mapply
可以对一个函数应用多个参数。在这里,参数是 (1) 数据框df
分为四个年龄组,以及 (2) probs*n
,它给出了我们想要从每个年龄组中获得的行数:
df.sample = mapply(a=split(df, df$age.groups), b=probs*n,
function(a,b) {
a[sample(1:nrow(a), b), ]
}, SIMPLIFY=FALSE)
mapply
返回一个包含四个数据帧的列表,每个数据帧一个。将此列表组合成一个数据框:
df.sample = do.call(rbind, df.sample)
检查抽样:
table(df.sample$age.groups)
[0,30) [30,51) [51,70) [70,Inf)
300 300 200 200
选项 2:包stratified
中的函数splitstackshape
该size
参数需要一个命名向量,其中包含每个层的样本数。
library(splitstackshape)
df.sample2 = stratified(df, "age.groups", size=probs*n)
选项 3:包strata
中的函数sampling
这个选项是迄今为止最慢的。
library(sampling)
# Data frame must be sorted by stratification column(s)
df = df[order(df$age.groups),]
sampled.rows = strata(df, 'age.groups', size=probs*n, method="srswor")
df.sample3 = df[sampled.rows$ID_unit, ]
选项 4:tidyverse
包
map2
就像mapply
它将两个参数并行应用于一个函数,在这种情况下是dplyr
包的sample_n
函数。map2
返回四个数据框的列表,每个层一个,我们将它们组合成一个数据框bind_rows
。
library(dplyr)
library(purrr)
df.sample4 = map2(split(df, df$age.groups), probs*n, sample_n) %>% bind_rows
计时
library(microbenchmark)
Unit: milliseconds
expr min lq mean median uq max neval cld
mapply 86.77215 110.82979 156.66855 123.95275 145.25115 486.2078 10 a
strata 5028.42933 5541.40442 5709.16796 5699.50711 5845.69921 6467.7250 10 b
stratified 38.33495 41.76831 89.93954 45.43525 79.18461 408.2346 10 a
tidyverse 71.48638 135.49113 143.12011 142.86866 155.72665 192.4174 10 a