2012-06-19 8 views
31

Próbuję utworzyć listę permutacji listy, tak, że na przykład perms(list("a", "b", "c")) powracaGenerowanie wszystkie odrębne permutacji listy w R

list(list("a", "b", "c"), list("a", "c", "b"), list("b", "a", "c"), 
    list("b", "c", "a"), list("c", "a", "b"), list("c", "b", "a")) 

Nie jestem pewien, jak postępować, jakakolwiek pomoc byłaby bardzo doceniana.

+0

Istnieje kilka pakietów do generowania permutacji w R. Napisałem ** [streszczenie] (https://stackoverflow.com/a/47983855/4408538) **, który zawiera odniesienia, a także demonstracje użycia dla każdej dostępnej metody. –

Odpowiedz

35

combinat::permn zrobi, że praca:

> library(combinat) 
> permn(letters[1:3]) 
[[1]] 
[1] "a" "b" "c" 

[[2]] 
[1] "a" "c" "b" 

[[3]] 
[1] "c" "a" "b" 

[[4]] 
[1] "c" "b" "a" 

[[5]] 
[1] "b" "c" "a" 

[[6]] 
[1] "b" "a" "c" 

Należy pamiętać, że kalkulacja jest ogromny, jeśli element jest duża.

24

Można spróbować permutations() z pakietu gtools, ale w odróżnieniu od combinatpermn(), że nie emituje listę:

> library(gtools) 
> permutations(3, 3, letters[1:3]) 
    [,1] [,2] [,3] 
[1,] "a" "b" "c" 
[2,] "a" "c" "b" 
[3,] "b" "a" "c" 
[4,] "b" "c" "a" 
[5,] "c" "a" "b" 
[6,] "c" "b" "a" 
+2

Zasługuje na to, że "permutacje" są bardziej elastyczne. Umożliwia permutację m n elementów i umożliwia wielokrotne użycie elementów. Znalazłem to po próbie 'permn' bez powodzenia. – mt1022

20

baza R może również stanowić odpowiedź:

all <- expand.grid(p1 = letters[1:3], p2 = letters[1:3], p3 = letters[1:3], stringsAsFactors = FALSE) 
perms <- all[apply(all, 1, function(x) {length(unique(x)) == 3}),] 
31

A gdy wracałem, musiałem to zrobić w bazie R bez ładowania żadnych pakietów.

permutations <- function(n){ 
    if(n==1){ 
     return(matrix(1)) 
    } else { 
     sp <- permutations(n-1) 
     p <- nrow(sp) 
     A <- matrix(nrow=n*p,ncol=n) 
     for(i in 1:n){ 
      A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i)) 
     } 
     return(A) 
    } 
} 

Zastosowanie:

> matrix(letters[permutations(3)],ncol=3) 
    [,1] [,2] [,3] 
[1,] "a" "b" "c" 
[2,] "a" "c" "b" 
[3,] "b" "a" "c" 
[4,] "b" "c" "a" 
[5,] "c" "a" "b" 
[6,] "c" "b" "a" 
+2

Dobra funkcja. Wydaje się też dość szybko. – A5C1D2H2I1M1N2O1R2T1

7

Spróbuj:

> a = letters[1:3] 
> eg = expand.grid(a,a,a) 
> eg[!(eg$Var1==eg$Var2 | eg$Var2==eg$Var3 | eg$Var1==eg$Var3),] 
    Var1 Var2 Var3 
6  c b a 
8  b c a 
12 c a b 
16 a c b 
20 b a c 
22 a b c 

Jak sugeruje @Adrian w komentarzach, ostatnia linia może być zastąpiony przez:

eg[apply(eg, 1, anyDuplicated) == 0, ] 
+0

lub, dla ostatniej linii: 'eg [apply (np. 1, anyDuplicated) == 0,]' – Adrian

+0

Dobra sugestia. – rnso

+0

@dusadrian Uwaga na temat skalowalności: Dwa razy pomyślałem, zanim zastosuję to podejście w "poważnym" kodzie, ponieważ szukana przestrzeń (np.) Rośnie nieproporcjonalnie, gdy wzrasta rozmiar próbki/próbkowanego zestawu (wskaźnik trafień: n! Vs. n^n - pogarsza się w przybliżeniu wykładniczo ze wzoru Stirlinga). Dla 10 na 10 przypadków współczynnik trafień wynosi już tylko "prod (1:10)/(10^10) = 0,036%". I wydaje się, że wszystkie te warianty są w pewnym momencie zapisane w pamięci, w ramce danych. Jednak zawsze podobało mi się to w przypadku małych zadań manualnych, ponieważ jest to łatwe do zrozumienia. – brezniczky

8
# Another recursive implementation  
# for those who like to roll their own, no package required 
    permutations <- function(x, prefix = c()) 
    { 
     if(length(x) == 0) return(prefix) 
     do.call(rbind, sapply(1:length(x), FUN = function(idx) permutations(x[-idx], c(prefix, x[idx])), simplify = FALSE)) 
    } 

    permutations(letters[1:3]) 
    # [,1] [,2] [,3] 
    #[1,] "a" "b" "c" 
    #[2,] "a" "c" "b" 
    #[3,] "b" "a" "c" 
    #[4,] "b" "c" "a" 
    #[5,] "c" "a" "b" 
    #[6,] "c" "b" "a" 
3

zabawy rozwiązanie „probabilistyczny” za pomocą próbki do bazy R:

elements <- c("a", "b", "c") 
k <- length(elements) 
res=unique(t(sapply(1:200, function(x) sample(elements, k)))) 
# below, check you have all the permutations you need (if not, try again) 
nrow(res) == factorial(k) 
res 

zasadzie można nazwać wiele losowych próbek, chcąc dostać je wszystkie, a ich wyjątkowy.

7

roztworu w podstawowej R, brak uzależnienia od innych pakietów:

> getPerms <- function(x) { 
    if (length(x) == 1) { 
     return(x) 
    } 
    else { 
     res <- matrix(nrow = 0, ncol = length(x)) 
     for (i in seq_along(x)) { 
      res <- rbind(res, cbind(x[i], Recall(x[-i]))) 
     } 
     return(res) 
    } 
} 

> getPerms(letters[1:3]) 
    [,1] [,2] [,3] 
[1,] "a" "b" "c" 
[2,] "a" "c" "b" 
[3,] "b" "a" "c" 
[4,] "b" "c" "a" 
[5,] "c" "a" "b" 
[6,] "c" "b" "a" 

Mam nadzieję, że to pomaga.

+1

Przdstawia rozwiązanie "gtools". – snoram

+0

Nie testowałem wcześniej, ale wydaje się, że tak. Chłodny. – Adrian

0

Co

pmsa <- function(l) { pms <- function(n) if(n==1) return(list(1)) else unlist(lapply(pms(n-1),function(v) lapply(0:(n-1),function(k) append(v,n,k))),recursive = F) lapply(pms(length(l)),function(.) l[.]) }

Daje listę. Następnie

pmsa(letters[1:3])