2015-04-22 95 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