#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])
делает то, что вы хотите. Я не знаю, почему пакет требует разных значений, если применить его к вектору через. В документации неясно.