2016-11-30 44 views
1

假设v=c(-1,-1,-1,0,0,0,1,1,1)并且我想要生成所有排列。有9!/(3!3!3!)=1680在R中生成不完全不同对象的所有可能排列

目前,我正在使用以下行来得到它,但它不是非常有效。

unique(replicate(100000, sample(v), simplify=FALSE)) 

这是一种可能的情况。我想概括这一点。假设n对象包含k不同的对象a1,a2,...,ak分别具有重复编号n1,n2,...,nk (n1+n2+...+nk=n)。然后n!/(n1!n2!...nk!)

我该如何有效地做到这一点?

回答

2

最简单的解决方法是使用iterpc

library(iterpc) 
getall(iterpc(table(v), ordered = TRUE)) 

它比ds440的combinat::permn方法至少快5000倍。

> system.time(unique(combinat::permn(v))) 
    user system elapsed 
    4.861 0.037 4.902 
> system.time(getall(iterpc(table(v), ordered = TRUE))) 
    user system elapsed 
    0.001 0.000 0.001 

和比sirallen方法快10倍。

> microbenchmark(getall(iterpc(table(v), ordered = TRUE)), sirallen()) 
Unit: microseconds 
            expr  min  lq  mean median 
getall(iterpc(table(v), ordered = TRUE)) 583.512 605.699 804.0107 748.9305 
           sirallen() 5784.122 7571.282 8777.4111 8256.1035 
2

试试这个:

u = list(unique(v)) 
Pv = expand.grid(rep(u,9)) 
Pv = Pv[rowSums(Pv==-1)==3 & rowSums(Pv==0)==3,] 
1

一种方法是使用排列函数生成所有的可能性,然后过滤。如果你需要所有可能性的保证,这与你的问题中的样本方法相比有优势,但是如果你有一个长向量,它可能会“崩溃”。

v=c(-1,-1,-1,0,0,0,1,1,1) 
unique(combinat::permn(v)) 

这种方法比@ sirallen的方法快得多。这种方法的推广可能是:

u <- unique(v) 
Pv <- expand.grid(rep(list(u),length(v))) 
for(i in seq_along(u)) { 
Pv <- Pv[rowSums(Pv==u[i])==sum(u[i]==v),] 
} 
dim(Pv)