Почему gtools::комбинации и перестановки не работают с вектором, содержащим одни и те же элементы?

#r #combinations #permutation

Вопрос:

Допустим, у меня есть вектор vec <- c("H", "H", "H", "H", "M", "M", "A", "A") Как мне получить все комбинации / перестановки, если я, например, рисую 5 из 8 с ожидаемым выходом.

 > head(t, 6)
     [,1] [,2] [,3] [,4] [,5]
[1,] "H"  "H"  "H"  "H"  "M" 
[2,] "H"  "H"  "H"  "H"  "M" 
[3,] "H"  "H"  "H"  "H"  "A" 
[4,] "H"  "H"  "H"  "H"  "A" 
[5,] "H"  "H"  "H"  "M"  "M" 
[6,] "H"  "H"  "H"  "M"  "A" 
 

Я пытался gtools::combinations() , но всегда получаю сообщение об ошибке, что слишком мало разных элементов (то же самое верно для gtools::permutations() независимо от того, разрешены ли повторы или нет.
Итак, я сделал это трудоемким способом

 t <- gtools::combinations(8, 5, vec, repeats.allowed = F)
Error in gtools::combinations(8, 5, vec, repeats.allowed = F) : 
  too few different elements


t <- gtools::combinations(8, 5, letters[1:8], repeats.allowed = F)

for ( i in 1:8) {
  if ( i <=4 ) {
    t[t == letters[i]] <- "H" 
  } else if (i <= 6) {
    t[t == letters[i]] <- "M" 
  } else if (i <= 8) {
    t[t == letters[i]] <- "A" 
  }
}

 

Я ищу более простое решение из любого пакета или базового R и хочу знать, почему оно не работает. Заранее спасибо.

Комментарии:

1. Вы действительно хотите включить повторяющиеся результаты? Например, в вашем желаемом выводе первые 2 строки идентичны. Вы собираетесь фильтровать их позже? Если это так, для этого существуют более прямые и эффективные алгоритмы.

2. Для небольших векторов я хотел бы сохранить его, но вы для большого вектора, который я хотел бы отфильтровать. Спасибо за ваше решение.

Ответ №1:

Альтернатива

 combn(vec,5)
 

в результате получается 56 комбинаций ( choose(8,5) ).

Комментарии:

1. Этого не знал. Это лучше, чем у меня, который опирался на пакет, о котором говорилось, так как он из утилит базового пакета, и чем меньше зависимостей, тем лучше

2. Спасибо за ответ. Это действительно полезно для конкретного случая, который я привел в качестве примера. Знаю только один другой случай expand.grid() , но я пропускаю другие случаи.

Ответ №2:

Когда вам нужны комбинации / перестановки вектора, который содержит повторы или мультимножества, многие из доступных функций в base R и других пакетах будут выдавать ненужные повторяющиеся результаты, которые в конечном итоге необходимо отфильтровать. Для небольших задач это не проблема, однако такой подход быстро становится непрактичным.

В настоящее время существует несколько пакетов, способных решать проблемы такого типа. Они arrangements и RcppAlgos (я автор).

 vec <- c("H", "H", "H", "H", "M", "M", "A", "A")
tbl_v <- table(vec)

tbl_v
vec
A H M 
2 4 2 

library(RcppAlgos)
comboGeneral(names(tbl_v), 5, freqs = tbl_v)
    [,1] [,2] [,3] [,4] [,5]
[1,] "A"  "A"  "H"  "H"  "H" 
[2,] "A"  "A"  "H"  "H"  "M" 
[3,] "A"  "A"  "H"  "M"  "M" 
[4,] "A"  "H"  "H"  "H"  "H" 
[5,] "A"  "H"  "H"  "H"  "M" 
[6,] "A"  "H"  "H"  "M"  "M" 
[7,] "H"  "H"  "H"  "H"  "M" 
[8,] "H"  "H"  "H"  "M"  "M"

## For package arrangements we have:
## arrangements::combinations(names(tbl_v), 5, freq = tbl_v)
 

Аналогично, для перестановок мы имеем:

 permuteGeneral(names(tbl_v), 5, freqs = tbl_v)
      [,1] [,2] [,3] [,4] [,5]
  [1,] "A"  "A"  "H"  "H"  "H" 
  [2,] "A"  "A"  "H"  "H"  "M" 
  [3,] "A"  "A"  "H"  "M"  "H" 
  [4,] "A"  "A"  "H"  "M"  "M" 
     .   .    .    .    .    .
     .   .    .    .    .    .
     .   .    .    .    .    .
[137,] "M"  "M"  "H"  "A"  "A" 
[138,] "M"  "M"  "H"  "A"  "H" 
[139,] "M"  "M"  "H"  "H"  "A" 
[140,] "M"  "M"  "H"  "H"  "H" 

## For package arrangements we have:
## arrangements::permutations(names(tbl_v), 5, freq = tbl_v)
 

Оба пакета содержат алгоритмы, которые генерируют каждый результат без необходимости фильтрации. Этот подход намного эффективнее.

Например, что, если бы у нас были big_vec <- rep(vec, 8) и мы хотели все комбинации длиной 16. Используя подход фильтрации, нужно было бы сгенерировать все комбинации вектора длиной 64, выбрать 16 и затем отфильтровать их. Это choose(64, 16) = 4.885269e 14 тотальные комбинации. Это будет непросто.

С этими двумя пакетами эта проблема решаема.

 big_vec <- rep(vec, 8)
tbl_big_v <- table(big_vec)

tbl_big_v
big_vec
 A  H  M 
16 32 16 

system.time(test_big <- comboGeneral(names(tbl_big_v), 16,
                                     freqs = tbl_big_v))
user  system elapsed 
   0       0       0 

dim(test_big)
[1] 153  16
 

Ответ №3:

apply(gtools::combinations(8,5,repeats.allowed = FALSE),2,(x) vec[x]) делает то, что вы хотите. Я не знаю, почему пакет требует разных значений, если применить его к вектору через. В документации неясно.