2015-04-22 47 views
2

我正在努力创建一个向量化的功能解决方案,这将允许我重复分层随机采样而无需在许多迭代中进行替换。我可以在不更换一次的情况下进行采样,然后从数据集中删除这些行,然后从未采样的观测值中重复该过程。不幸的是,我需要做很多次这使得这个手动选项不可能。复制分层随机采样无需替换R

我已经尝试过使用replicate()函数,但是我只能让它每次通过都没有替换样本。它将选定的样本放回数据集中以便进行下一次采样。

使用下面的代码,我希望函数创建30个新的数据集,这些数据集由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”。

即使我能弄清楚如何解决向量化函数中的采样问题,我真的不知道如何让函数创建新的数据集并适当地命名它们。

如果有人能为我提供一些帮助,我将不胜感激。感谢您花时间阅读我的文章。

回答

1

如果我理解你想要的东西正确,这里有一个解决方案。

首先只是采样整个矢量,也就是说,你只是要行号随机排序:

sample_rows <- sample(nrow(one)) 

然后分配一个样本组的每个随机分布的行(3个元素由基团) 。由于元素的数量可能不能被3整除,所以扩展矢量的长度使其与行数相同。现在填写的NA与下一组(我认为这是你所说的“剩余的最后一组”的意思):

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 

所以,现在你有3个24个样本和两个1个样本,无需更换:

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”的向量,但你可以很容易地复制零向量并将它们合并。

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 
+1

我想你'sample_group'创作可以像'0被简化:(nrow(之一)-1)%/%3',但+ 1否则:-) – A5C1D2H2I1M1N2O1R2T1

+0

对不起,如果我的问题不清楚。基本上我所要做的就是从一个数据集开始,一个数据集由零和一列中的一个观察值组成,然后我想创建30个由3个随机零观察值和3个随机观察值组成的新数据集(共6行) 。余下的评论意味着零和总数不总是可以被3整除。在我上面的例子中,有86个零开始,这意味着我们应该在每个新集合中真正地放置2.86个零。 @Carlos Cinelli – Brian

+0

谢谢你的评论。这比我期待的更简单,但我相信如果有一种方法可以实现下一步的自动化,那么它就可以工作。既然每个观察都被分配到一个样本组,那么是否有一种方法可以通过“sample_group”数字自动将它们拉出并为每个组编号创建新的数据集?那么“new_dat1”,“new_dat2”....“new_dat30”?谢谢! @CarlosCinelli – Brian