2014-09-20 135 views
17

我試圖從0到7(有替換)隨機抽樣7個數字,但受制於所選數字加起來爲7的約束。因此,例如,輸出0 1 1 2 3 0 0沒問題,但輸出1 2 3 4 5 6 7沒有。有沒有辦法使用示例命令添加約束?R:sample()命令受到約束

我打算使用replicate()函數與示例命令作爲參數,從示例命令返回N個不同的向量列表。我目前使用示例命令(沒有任何約束)的方式,我需要非常大,以獲得儘可能多的可能的矢量,總和爲7。我認爲必須有一個更簡單的方法來做到這一點!

這裏是我的那部分代碼:

x <- replicate(100000, sample(0:7, 7, replace=T))  

理想情況下,我想在×10,000或100,000向量總和爲7,但需要一個巨大的N值來做到這一點。謝謝你的幫助。

+0

這正是我原來的樣子。我拿了這個x變量的一個子集,但是N = 100000,這個子集還是很小的。該子集甚至非常小,N = 1000000,更不用說它需要一段時間才能運行! – 2014-09-20 17:09:22

+0

你可能需要使用組合**如果**你想從所有可能的組合中得到一個統一的樣本... – Spacedman 2014-09-20 17:15:19

+1

'partitions :: parts(7)'給你所有的分區(將整數分成一個總和),這可能是答案的組成部分... – 2014-09-20 17:31:34

回答

18

要確保你均勻採樣,你可以只生成所有排列並限制那些總和7:

library(gtools) 
perms <- permutations(8, 7, 0:7, repeats.allowed=T) 
perms7 <- perms[rowSums(perms) == 7,] 

nrow(perms7),我們看到的只有1716種可能的排列那筆7.現在你可以從排列均勻的樣品:

set.seed(144) 
my.perms <- perms7[sample(nrow(perms7), 100000, replace=T),] 
head(my.perms) 
#  [,1] [,2] [,3] [,4] [,5] [,6] [,7] 
# [1,] 0 0 0 2 5 0 0 
# [2,] 1 3 0 1 2 0 0 
# [3,] 1 4 1 1 0 0 0 
# [4,] 1 0 0 3 0 3 0 
# [5,] 0 2 0 0 0 5 0 
# [6,] 1 1 2 0 0 2 1 

這種方法的優點是,它很容易地看到,我們正在取樣統一隨機。此外,這是相當快 - 建設perms7在我的電腦上花了0.3秒,並建立一百萬行my.perms花了0.04秒。如果你需要繪製多個矢量,這將比遞歸方法快得多,因爲你只是使用矩陣索引到perms7而不是分別生成每個矢量。

這裏的數字的計數的樣本分佈:

#  0  1  2  3  4  5  6  7 
# 323347 188162 102812 51344 22811 8629 2472 423 
8

開始與所有零,添加一個到任何元素,做7次:

sumTo = function(){ 
    v = rep(0,7) 
    for(i in 1:7){ 
     addTo=sample(7)[1] 
     v[addTo]=v[addTo]+1 
    } 
    v 
} 

或者等價地,只需選擇你要長7的一個樣本遞增7元,那麼製表那些,確保您製表高達7:

sumTo = function(){tabulate(sample(7, 7, replace = TRUE), 7)} 


> sumTo() 
[1] 2 1 0 0 4 0 0 
> sumTo() 
[1] 1 3 1 0 1 0 1 
> sumTo() 
[1] 1 1 0 2 1 0 2 

我不知道這是否會產生從所有可能組合的統一樣本...

IND的分配100,000個以上的個人元素是:

> X = replicate(100000,sumTo()) 
> table(X) 
X 
    0  1  2  3  4  5  6 
237709 277926 138810 38465 6427 627  36 

那個時候沒打到0,0,0,0,0,7!

+5

我想你可以寫這個'表格(樣本(7,7,replace = TRUE),7)'。 – flodel 2014-09-20 17:29:24

+2

這看起來在算法上是等價的,非常整齊。我吮吸。 – Spacedman 2014-09-20 17:36:02

5

與其他解決方案相比,此遞歸算法將輸出對於大數字具有更高概率的分佈。我們的想法是扔一個隨機數y0:7在任何七個可用插槽,然後在0:(7-y)用隨機數重複,等:

sample.sum <- function(x = 0:7, n = 7L, s = 7L) { 
    if (n == 1) return(s) 
    x <- x[x <= s] 
    y <- sample(x, 1) 
    sample(c(y, Recall(x, n - 1L, s - y))) 
} 

set.seed(123L) 
sample.sum() 
# [1] 0 4 0 2 0 0 1 

繪圖100000個載體把11秒我的機器上,在這裏是分配我得到:

#  0  1  2  3  4  5  6  7 
# 441607 98359 50587 33364 25055 20257 16527 14244 
+0

重複10萬用了8秒用我的方法,並且我得到了一個'c(0,0,7,0,0,0,0)'! – Spacedman 2014-09-20 17:30:58

+0

算法獲得7的概率是7^6或117,649中的一個。我想這是由OP決定他想要什麼樣的分配。 – flodel 2014-09-20 17:33:21

+0

實際上有8個可能的值(0-7),所以實際上有8^7 = 2,097,152個7長度的置換。在我的回答中,我發現只有1716個總和爲7,所以我預計向量'c(0,0,7,0,0,0,0)'的58個發生率。只有獲得一個可能是沒有統一抽樣的證據。 – josliber 2014-09-20 17:40:48

5

有可能是一個更容易和/或更優雅的方式,但這裏的使用LSPM:::.nPri功能的窮舉法。鏈接包括對於那些感興趣的算法的R-only版本的定義。

#install.packages("LSPM", repos="http://r-forge.r-project.org") 
library(LSPM) 
# generate all possible permutations, since there are only ~2.1e6 of them 
# (this takes < 40s on my 2.2Ghz laptop) 
x <- lapply(seq_len(8^7), nPri, n=8, r=7, replace=TRUE) 
# set each permutation that doesn't sum to 7 to NULL 
y <- lapply(x, function(p) if(sum(p-1) != 7) NULL else p-1) 
# subset all non-NULL permutations 
z <- y[which(!sapply(y, is.null))] 

現在你可以從z採樣和放心,你得到總計爲7

+0

我看到josilber建議同樣的事情。我會離開這個答案是另一種選擇。 – 2014-09-20 18:07:48

3

我發現這個問題有趣的置換,並給它一些額外的思考。 R(sample())中的另一種(更一般的)從所有可行解中均勻採樣的方法(不會產生並存儲所有置換(這在7個數字中顯然不可能),可以是簡單的MCMC執行:

S <- c(0, 1, 1, 2, 3, 0, 0) #initial solution 
N <- 100 #number of dependent samples (or burn in period) 
series <- numeric(N) 
for(i in 1:N){ 
    b <- sample(1:length(S), 2, replace=FALSE) #pick 2 elements at random 
    opt <- sum(S[-b]) #sum of complementary elements 
    a <- sample(0:(7-opt), 1) #sample a substistute 
    S[b[1]] <- a #change elements 
    S[b[2]] <- 7 - opt - a 
} 
S #new sample 

這對於一些樣本來說當然非常快。 「分佈」:

#"distribution" N=100.000:  0  1  2  3  4  5  6  7 
#       321729 189647 103206 52129 22287 8038 2532 432 

當然,在這種情況下,它實際上是可以找到並存儲所有組合,如果你想從所有可能的結果有巨大的樣品,只是使用partitions::compositions(7, 7),因爲也由Josh建議O'Brien在評論中,爲了避免計算所有排列,當只需要一小部分時:

perms7 <- partitions::compositions(7, 7) 

>tabulate(perms7[, sample(ncol(perms7), 100000, TRUE)]+1, 8) 
#"distribution" N=100.000:  0  1  2  3  4  5  6  7 
#       323075 188787 102328 51511 22754 8697 2413 435