在 R 中复制分层随机抽样而不进行替换
Replicate Stratified Random Sampling without Replacement in R
我正在努力创建一个矢量化函数解决方案,该解决方案将允许我在多次迭代中无需替换即可复制分层随机抽样。我能够在不替换的情况下进行一次采样,然后从数据集中删除这些行,然后从未采样的观察中重复该过程。不幸的是,我需要多次执行此操作,因此无法使用此手动选项。
我试过使用 replicate() 函数,但是我只能让它在每次通过时都没有替换的样本。它将选择的样本放回数据集中以供下一次抽样。
使用下面的代码,我想要创建 30 个新数据集的函数,这些数据集由 "one" 和 "zero" 集中的 3 个唯一(以前未采样)行组成。因此,每个新数据集将有 6 个总观测值(3-1 和 3-0),并被命名为唯一的名称(即 "new_dat1"、"new_dat2"..."new_dat30")。
如果可能的话,我希望在不使用 for 循环的情况下实现所有这些,因此首选 "apply" 系列中的东西。
set.seed(123)
dat <- data.frame(Outcome = round(runif(160, 0, 1)))
cust <- data.frame(Cust = rep(c("ABC", "DEF", "GHI"), c(45, 80, 35)))
dat <- cbind(cust, dat)
one <- subset(dat, Outcome == 1)
zero <- subset(dat, Outcome == 0)
# Manual option which is not sufficient
################################################
# sample 1's and remove choosen obs from "one" dataset
set.seed(123)
index <- sample(1:nrow(one), 3, replace = FALSE)
new_dat1 <- one[index, ]
unused_one <- one[-index, ]
# sample 0's and remove choosen obs from "zero" dataset
set.seed(123)
index <- sample(1:nrow(zero), 3, replace = FALSE)
unused_zero <- zero[-index, ]
# combine the 3-1 and 3-0 samples into the first of 30 "new_datn" sets
new_dat1 <- rbind(new_dat1, zero[index, ])
# repeat, now sampling from "unused_one" and "unused_zero" to create "new_dat2" - "new_dat30"
################################################
# Failed attempt using the replicate() function
################################################
set.seed(123)
one_sample <- replicate(30, one[sample(nrow(one), 3, replace = FALSE), ], simplify = FALSE)
zero_sample <- replicate(30, zero[sample(nrow(zero), 3, replace = FALSE), ], simplify = FALSE)
让这件事变得更加复杂的是,我在 "dat" 集中观察到的 0 和 1 的总数会不时变化,所以我可能总是有余数要处理。因此,该函数必须能够为每个 "new_dat" 采样 3,直到它遇到最终集合的余数,无论值如何,它都可以进入最终的 "new_dat"。
即使我能弄清楚如何解决矢量化函数中的采样问题,我也真的会不知所措让函数创建新的数据集并适当地命名它们。
如果有人能为我提供一些帮助,我将不胜感激。感谢您花时间阅读我的 post。
如果我理解正确,这是一种解决方案。
首先对整个向量进行采样,也就是说,您只是要对行号进行随机排序:
sample_rows <- sample(nrow(one))
然后为每个随机分布的行分配一个样本组(每组 3 个元素)。由于元素的数量可能不能被 3 整除,因此延长向量的长度,使其与行数的长度相同。现在用下一组填充 NA(我想这就是你所说的 "remainder for the final set" 的意思):
sample_group <- rep(1:(length(sample_rows)%/% 3), each = 3)
length(sample_group) <- length(sample_rows)
sample_group[is.na(sample_group)] <- max(sample_group, na.rm = TRUE) + 1
所以现在你有 24 个样本 3 和 1 个样本 2,没有替换:
samples <- data.frame(sample_rows, sample_group)
head(samples)
sample_rows sample_group
1 12 1
2 6 1
3 41 1
4 35 2
5 71 2
6 62 2
tail(samples)
sample_rows sample_group
69 69 23
70 53 24
71 32 24
72 27 24
73 18 25
74 65 25
我为 "one"s 的向量做了这个,但你可以很容易地为零的向量复制它并组合它们。
PS:您可以使用 split()
和 lapply()
从 data.frame 中提取行。例如:
new_dat <- lapply(split(samples$sample_rows, samples$sample_group), function(x) one[x,])
所以 new_dat
是一个包含所有 25 data.frames
的列表。例如:
new_dat[[8]] # gives you the eigth data.frame
或:
new_dat[[25]] # gives you the last data.frame
我正在努力创建一个矢量化函数解决方案,该解决方案将允许我在多次迭代中无需替换即可复制分层随机抽样。我能够在不替换的情况下进行一次采样,然后从数据集中删除这些行,然后从未采样的观察中重复该过程。不幸的是,我需要多次执行此操作,因此无法使用此手动选项。
我试过使用 replicate() 函数,但是我只能让它在每次通过时都没有替换的样本。它将选择的样本放回数据集中以供下一次抽样。
使用下面的代码,我想要创建 30 个新数据集的函数,这些数据集由 "one" 和 "zero" 集中的 3 个唯一(以前未采样)行组成。因此,每个新数据集将有 6 个总观测值(3-1 和 3-0),并被命名为唯一的名称(即 "new_dat1"、"new_dat2"..."new_dat30")。
如果可能的话,我希望在不使用 for 循环的情况下实现所有这些,因此首选 "apply" 系列中的东西。
set.seed(123)
dat <- data.frame(Outcome = round(runif(160, 0, 1)))
cust <- data.frame(Cust = rep(c("ABC", "DEF", "GHI"), c(45, 80, 35)))
dat <- cbind(cust, dat)
one <- subset(dat, Outcome == 1)
zero <- subset(dat, Outcome == 0)
# Manual option which is not sufficient
################################################
# sample 1's and remove choosen obs from "one" dataset
set.seed(123)
index <- sample(1:nrow(one), 3, replace = FALSE)
new_dat1 <- one[index, ]
unused_one <- one[-index, ]
# sample 0's and remove choosen obs from "zero" dataset
set.seed(123)
index <- sample(1:nrow(zero), 3, replace = FALSE)
unused_zero <- zero[-index, ]
# combine the 3-1 and 3-0 samples into the first of 30 "new_datn" sets
new_dat1 <- rbind(new_dat1, zero[index, ])
# repeat, now sampling from "unused_one" and "unused_zero" to create "new_dat2" - "new_dat30"
################################################
# Failed attempt using the replicate() function
################################################
set.seed(123)
one_sample <- replicate(30, one[sample(nrow(one), 3, replace = FALSE), ], simplify = FALSE)
zero_sample <- replicate(30, zero[sample(nrow(zero), 3, replace = FALSE), ], simplify = FALSE)
让这件事变得更加复杂的是,我在 "dat" 集中观察到的 0 和 1 的总数会不时变化,所以我可能总是有余数要处理。因此,该函数必须能够为每个 "new_dat" 采样 3,直到它遇到最终集合的余数,无论值如何,它都可以进入最终的 "new_dat"。
即使我能弄清楚如何解决矢量化函数中的采样问题,我也真的会不知所措让函数创建新的数据集并适当地命名它们。
如果有人能为我提供一些帮助,我将不胜感激。感谢您花时间阅读我的 post。
如果我理解正确,这是一种解决方案。
首先对整个向量进行采样,也就是说,您只是要对行号进行随机排序:
sample_rows <- sample(nrow(one))
然后为每个随机分布的行分配一个样本组(每组 3 个元素)。由于元素的数量可能不能被 3 整除,因此延长向量的长度,使其与行数的长度相同。现在用下一组填充 NA(我想这就是你所说的 "remainder for the final set" 的意思):
sample_group <- rep(1:(length(sample_rows)%/% 3), each = 3)
length(sample_group) <- length(sample_rows)
sample_group[is.na(sample_group)] <- max(sample_group, na.rm = TRUE) + 1
所以现在你有 24 个样本 3 和 1 个样本 2,没有替换:
samples <- data.frame(sample_rows, sample_group)
head(samples)
sample_rows sample_group
1 12 1
2 6 1
3 41 1
4 35 2
5 71 2
6 62 2
tail(samples)
sample_rows sample_group
69 69 23
70 53 24
71 32 24
72 27 24
73 18 25
74 65 25
我为 "one"s 的向量做了这个,但你可以很容易地为零的向量复制它并组合它们。
PS:您可以使用 split()
和 lapply()
从 data.frame 中提取行。例如:
new_dat <- lapply(split(samples$sample_rows, samples$sample_group), function(x) one[x,])
所以 new_dat
是一个包含所有 25 data.frames
的列表。例如:
new_dat[[8]] # gives you the eigth data.frame
或:
new_dat[[25]] # gives you the last data.frame