Что происходит, когда вам нужен определенный тип рандомизации?

Обзор генерации случайных чисел в R

R имеет не менее 20 функций генератора случайных чисел. Каждый использует определенное распределение вероятностей для создания чисел. Все требуют, чтобы вы указали количество случайных чисел, которое вы хотите (на изображении выше показано 200). Все они доступны в базовой версии R - пакеты не требуются.

Распространенные распределения генератора случайных чисел:

  • Нормальный (rnorm): среднее значение по умолчанию 0 и стандартное отклонение 1
  • Binomial (rbinom): без значений по умолчанию, укажите количество испытаний и вероятность успеха в каждом испытании.
  • Uniform (runif): минимальное значение по умолчанию 0 и максимальное значение 1

Из трех вышеупомянутых только генератор биномиальных случайных чисел создает целые числа.

Зачем создавать случайные числа?

Проблемы, связанные со случайными числами, очень распространены - на Stack Exchange около 50 000 вопросов, касающихся случайных чисел.

Но зачем их использовать?

Случайные числа имеют множество практических приложений. Они используются в симуляциях Монте-Карло. Они используются в криптографии. Они использовались для создания контента CAPTCHA. Они используются в игровых автоматах. Они также использовались для более простых задач, таких как создание случайного порядка сортировки для массива упорядоченных данных.

Проблемы со случайными числами

Часто задаваемые вопросы включают «действительно ли мои случайные числа случайны?» и «как я могу генерировать неповторяющиеся случайные числа?»

Примечание: последнее снижает случайность, поскольку совокупность возможных случайных чисел уменьшается на единицу каждый раз, когда выпадает случайное число. Этот метод подходит для таких ситуаций, как лотереи или бинго, где каждый билет или шар можно разыграть только один раз.

Эта проблема порождает еще одну проблему! Произвольно сгенерированные выборки без замещающих чисел должны быть целыми числами. Ни у кого нет билета 5,6932 или шара для бинго 0,18967.

Практический пример задач со случайными числами

Возьмем, к примеру, 20 студенток того же возраста. У меня есть четыре метода обучения, которые я хочу опробовать. Я хочу опробовать только один метод обучения для каждого ученика. Простая математика. Мне нужно по пять учеников в каждой группе.

Но как мне сделать это, чтобы каждый ученик был назначен случайным образом?

И как мне убедиться, что у меня производятся только целые числа?

И как мне все это сделать, используя случайно сгенерированные числа без замены? Например, я не хочу, чтобы в одной группе было шесть учеников, а в другой - четверо.

Во-первых, мне нужно создать фиктивные данные в R. Давайте создадим этот список фиктивных студенток.

FemaleStudents <- data.frame(Names=c("Alice", "Betty", "Carol", "Denise", "Erica", "Frances", "Gina", "Helen", "Iris", "Julie", "Katherine",
                           "Lisa", "Michelle", "Ngaire", "Olivia", "Penelope", "Rachel", "Sarah", "Trudy", "Uma"))

Теперь у нас есть одномерный набор данных из 20 наших студентов.

Мы знаем, что функция runif() не создает целые числа. Почему бы нам не округлить случайные числа, чтобы получить только целые числа и использовать эту функцию? Мы можем заключить случайное число в функцию округления.

Вопрос 1: почему я использую случайное равномерное распределение, а не другое, например, случайное нормальное распределение?

В R. есть пять типов функций округления. Мы будем использовать round().

Чтобы получить те же результаты, я установлю начальное число для генерации случайных чисел. Каждый раз, когда мы генерируем случайные числа, мы будем использовать одно и то же начальное число. Я выбрал 5 в качестве семени. Если вы не установите семя, или если вы установите семя, отличное от 5, ваши результаты будут отличаться от моих.

set.seed(5)
FemaleStudents$Group <- round(runif(20, 1, 5))

Что ж, похоже, это сработало. Мы распределяем каждого студента в группы от 1 до 5.

Давайте дважды проверим наше распределение.

table(FemaleStudents$Group)
1 2 3 4 5 
2 6 5 4 3

Штопать. Только одна из пяти групп имеет правильное количество учеников (группа 4). Почему это случилось?

Мы можем проверить фактически выводимые числа с помощью runif() без округления и разрешить вывод на консоль. Здесь вывод печатается, потому что я не назначил функцию объекту (например, переменной data.frame).

set.seed(5)
runif(20,1,5)
[1] 1.800858 3.740874 4.667503 2.137598 1.418601 3.804230 3.111840 4.231741 4.826001 1.441812 2.093140 2.962053 2.273616 3.236691 2.050373
[16] 1.807501 2.550103 4.551479 3.219690 4.368718

Как видим, проблема была в округлении. Но если бы мы не округляли, каждый ученик был бы отнесен к разной группе.

Что мы делаем?

образец()

sample() теперь одна из моих любимых функций в R. Давайте посмотрим, как это работает.

Случайным образом распределить по группам одинакового размера (имеет значение)

Как мы можем использовать его для случайного распределения наших 20 студентов в четыре группы одинакового размера?

Что произойдет, если мы попробуем sample() нормально?

set.seed(5)
FemaleStudents$Sample <- sample(1:5, nrow(FemaleStudents), replace=TRUE)

Вопрос 2: какой результат вы получили, когда использовали table(FemaleStudents$Sample)?

Мы можем решить эту проблему, создав вектор номеров групп, а затем используя выборку без замены из этого вектора. Команда rep используется для создания диапазона повторяющихся значений. Вы можете использовать его для повторения каждого числа в серии, как я использовал здесь. Число 1 повторяется четыре раза, затем число 2 повторяется четыре раза и так далее. Вы также можете использовать его для повторения последовательности чисел, если вместо этого используете этот код: rep(1:5,4)

OurGroups <- rep(1:5, each=4)
set.seed(5)
FemaleStudents$Sample <- sample(OurGroups, nrow(FemaleStudents), replace=FALSE)

Мы использовали наш вектор чисел (OurGroups), чтобы распределить наших студентов по группам. Мы использовали выборку без замены (replace=FALSE) из OurGroups, потому что нам нужно использовать каждое значение в этом векторе. Нам нужно удалить каждое значение по мере его использования.

И мы получаем желаемый результат!

table(FemaleStudents$Sample)
1 2 3 4 5 
4 4 4 4 4

Вопрос 3: почему я все же установил семя?

Еще одно преимущество sample() в том, что он не заботится о типе. Мы можем повторить распределение, используя вектор строк. Это может быть полезно, если вы не хотите снова и снова возвращаться к тому, что означает «1».

OurNamedGroups <- rep(c("Up", "Down", "Charmed", "Strange", "Top"), each=4)
set.seed(5)
FemaleStudents$Sample2 <- sample(OurNamedGroups, nrow(FemaleStudents), replace=FALSE)
table(FemaleStudents$Sample2)
Charmed    Down Strange     Top      Up 
      4       4       4       4       4

Поскольку мы использовали одно и то же начальное число, мы можем видеть, что было выполнено одно и то же распределение студентов, независимо от того, использовали ли мы числовые или символьные данные для задания.

table(FemaleStudents$Sample,FemaleStudents$Sample2)
   
    Charmed Down Strange Top Up
  1       0    0       0   0  4
  2       0    4       0   0  0
  3       4    0       0   0  0
  4       0    0       4   0  0
  5       0    0       0   4  0

Распределить случайным образом, если размер группы не ограничен

Иногда мы хотим распределить по группам случайным образом, но у нас нет вектора групп. Мы по-прежнему распределяем каждую единицу (человека, овцу, кусок сыра) только в одну группу и используем полностью случайное распределение.

Допустим, в нашей школе есть новый специальный библиотечный зал. Он был построен со звукоизоляцией, чтобы студентам было удобнее учиться. Главный библиотекарь хотел бы узнать об опыте студентов в этой комнате. Проблема только в том, что помещение ограничено по размеру. Главный библиотекарь считает, что около четырех студентов - это достаточно большая группа, чтобы дать первоначальную обратную связь.

Опять же, мы можем использовать sample() для выбора наших студенческих групп. В данном случае у нас есть «студенты, которые будут проверять комнату» и «студенты, которые не будут проверять комнату». Я назову их «Тест» и «Не тест». Эти ярлыки были выбраны из-за того, что они 1. короткие и 2. легко различимые.

Поскольку раньше мы делали выборку без замены, мы не указывали вероятности отнесения к группам - мы просто вытаскивали назначение из вектора. Теперь воспользуемся выборкой с заменой. С заменой относится к группе, а не к студентам.

Нам нужно произвести выборку с заменой, так как у нас всего две группы («Тест», «Не тест») и 20 студентов. Если мы попытаемся выполнить выборку без замены, наш код выдаст ошибку.

Наш код очень похож:

set.seed(5)
FemaleStudents$Library <- sample(c("Test", "Not test"), nrow(FemaleStudents), replace=TRUE, prob=c(4/20,16/20))
table(FemaleStudents$Library)
Not test     Test 
      15        5

Как видите, для тестирования комнаты мы выделили пять студентов, а не четверых. Такой результат ожидается при работе с небольшими образцами. Однако мы распределяем студентов совершенно случайно. У каждого студента была одинаковая вероятность быть назначенным для тестирования комнаты. Были ли предыдущие студенты тестировщиками или нет, это никак не повлияло на распределение следующего студента.

Давайте пройдемся по этому коду.

Я создал новую переменную в data.frame для сбора распределения (Library).

Вместо того, чтобы иметь дело с числами для названий групп, я использовал строки, о которых упоминал ранее. Поскольку я использовал строки, c() должен заключать имена групп (“Test”, “Not test”), а каждое имя группы разделяется запятой.

Замена была установлена ​​на TRUE.

Должна быть указана вероятность отнесения к любой группе. Это prob=c(4/20,16/20) часть функции sample(). Опять же, обратите внимание, как c() используется для хранения вероятностей. Также интересно то, что вероятности могут быть выражены в виде дробей, а не десятичных знаков.

Ура образец ()

Я использую sample() все время для работы, которую делаю. Возможность использовать строки, а также ограничивать числовой вывод целыми числами (и определять желаемый диапазон целых чисел) дает мне больше контроля, чем попытка использовать одну из функций случайных чисел.

Ответы

Ответ 1: я использовал случайное равномерное распределение, потому что хотел, чтобы каждое значение было равновероятным.

Ответ 2: я получил такой вывод:

1 2 3 4 5 
2 7 4 2 5

Ответ 3: Если мы не устанавливаем начальное значение или используем другое, распределение отдельных учащихся будет другим. Например, когда начальное число равно 5, Алиса выделяется в группу 2. Если начальное значение равно 7, Алиса выделяется в группу 5. Репликация важна, когда код необходимо повторно запустить (например, при тестировании).