Если в R установить set.seed (), а затем использовать функцию примера для рандомизации списка, могу ли я гарантировать, что не сгенерирую такую же перестановку?
то есть ...
set.seed(25)
limit <- 3
myindex <- seq(0,limit)
for (x in seq(1,factorial(limit))) {
permutations <- sample(myindex)
print(permutations)
}
Это производит
[1] 1 2 0 3
[1] 0 2 1 3
[1] 0 3 2 1
[1] 3 1 2 0
[1] 2 3 0 1
[1] 0 1 3 2
будут ли все напечатанные перестановки уникальными? Или есть шанс, основываясь на том, как это реализовано, чтобы я мог получить несколько повторов?
Я хочу быть в состоянии сделать это без повторов, гарантировано. Как бы я это сделал?
(Я также хочу избежать использования функции вроде permn (), которая имеет очень механистический метод для генерации всех перестановок - она не выглядит случайной.)
Кроме того, sidenote --- похоже, что эта проблема O ((n!)!), Если я не ошибаюсь.
r
sampling
combinatorics
resampling
Mittenchops
источник
источник
limit
превышает 12, вы, скорее всего, исчерпаете ОЗУ, когда R попытается выделить место дляseq(1,factorial(limit))
. (12! Требуется около 2 ГБ, поэтому 13! Потребуется около 25 ГБ, 14! Около 350 ГБ и т. Д.)Ответы:
Вопрос имеет много веских толкований. Комментарии - особенно те, которые указывают на необходимость перестановки 15 или более элементов (15! = 1307674368000 становится все больше) - предполагают, что нужна сравнительно небольшая случайная выборка без замены всех n! = n * (n-1) (n-2) ... * 2 * 1 перестановок 1: n. Если это правда, существуют (несколько) эффективные решения.
Следующая функция
rperm
принимает два аргументаn
(размер перестановок для выборки) иm
(количество перестановок размера n для рисования). Если m достигает или превышает n !, функция займет много времени и вернет много значений NA: она предназначена для использования, когда n относительно велико (скажем, 8 или более) и m намного меньше, чем n !. Он работает, кэшируя строковое представление найденных к настоящему времени перестановок, а затем генерируя новые перестановки (случайным образом), пока не будет найдена новая. Он использует ассоциативную способность индексации списка R для быстрого поиска в списке ранее найденных перестановок.Природа
replicate
состоит в том, чтобы возвращать перестановки как векторы столбцов ; например , следующее воспроизводит пример в исходном вопросе, транспонированный :Время отлично подходит для малых и средних значений m, примерно до 10000, но ухудшается для более серьезных проблем. Например, образец m = 10000 перестановок из n = 1000 элементов (матрица из 10 миллионов значений) был получен за 10 секунд; выборка из m = 20 000 перестановок из n = 20 элементов потребовала 11 секунд, хотя выходной результат (матрица из 400 000 записей) был намного меньше; и вычислительная выборка m = 100 000 перестановок из n = 20 элементов была прервана через 260 секунд (у меня не хватило терпения ждать завершения). Эта проблема масштабирования, по-видимому, связана с неэффективностью масштабирования в ассоциативной адресации R. Можно обойти это, создавая выборки в группах, скажем, 1000 или около того, затем объединяя эти выборки в большую выборку и удаляя дубликаты.
редактировать
Вот некоторые истекшие времена в секундах для диапазона размеров перестановок и количества запрошенных различных перестановок:
(Очевидно, что аномальное ускорение от size = 10 до size = 15 связано с тем, что первый уровень кэша больше для size = 15, что уменьшает среднее количество записей в списках второго уровня, тем самым ускоряя ассоциативный поиск R. стоимость в оперативной памяти, выполнение может быть сделано быстрее за счет увеличения размера кэша верхнего уровня.Просто увеличение
k.head
на 1 (что увеличивает размер верхнего уровня на 10) ускорилось, например,rperm(100000, size=10)
с 11,77 до 8,72 секунд. кэш увеличился в 10 раз, но не получил заметного прироста (8,51 секунды).За исключением случая 1 000 000 уникальных перестановок из 10 элементов (значительная часть всех 10! = Около 3,63 млн. Таких перестановок), столкновения практически не обнаруживались. В этом исключительном случае было 169 310 столкновений, но не было полных отказов (фактически был получен миллион уникальных перестановок).
Рабочий код следует.
источник
> rperm(6,3) $failures [1] 9 $sample [,1] [,2] [,3] [1,] 3 1 3 [2,] 2 2 1 [3,] 1 3 2 [4,] 1 2 2 [5,] 3 3 1 [6,] 2 1 3
Использование
unique
в правильном направлении должно сделать трюк:источник
Я немного перейду к первому вопросу и предположу, что если вы имеете дело с относительно короткими векторами, вы можете просто сгенерировать все перестановки, используя
permn
их, и случайным образом упорядочить их с помощьюsample
:источник
permn(10)
или что-то еще только один раз.set.seed
: она описывает, как сохранить состояние ГСЧ и восстановить его позже.