set.seed() идёт первым
Случайные выборки, меняющиеся при каждом запуске, бесполезны для обучения, проверки, отладки и науки: если ваша симуляция говорит 0.146 сегодня и 0.153 завтра, какое число пойдёт в отчёт? set.seed() фиксирует начальную точку генератора, делая весь последующий поток «случайности» в точности повторяемым:
Одно зерно — одинаковые выборки, каждый раз, на любой машине. Числа являются псевдослучайными: детерминированная последовательность, сконструированная так, чтобы проходить любые статистические тесты на случайность, а зерно выбирает, где в этой последовательности вы стартуете. Само значение зерна не несёт смысла — 42, 7, 20260807, — берите что угодно, только запишите. Привычка, которую стоит выработать: один set.seed() в начале любого скрипта, использующего случайность. (Учтите, что потребление выборок продвигает состояние, поэтому для воспроизводимости важен и порядок вызовов.)
Система d/p/q/r: одна таблица расшифровывает всю библиотеку
R именует каждую функцию распределения как префикс + семейство, и, увидев эту сетку, вы сможете читать всю статистическую библиотеку:
| Префикс | На какой вопрос отвечает | Пример для нормального |
|---|---|---|
r | Дай мне случайные значения | rnorm(5) |
d | Плотность: какова высота кривой в точке x? | dnorm(0) |
p | Вероятность: P(X ≤ x)? | pnorm(1.96) |
q | Квантиль: какой x стоит на этом процентиле? | qnorm(0.975) |
p и q являются обратными друг другу, и это та пара, с которой вы встретились в доверительных интервалах в виде qt(0.975, df):
Замените имя семейства — и всё переносится: runif/dunif/punif/qunif, rbinom/..., rpois/..., rt/..., rexp/.... Выучите четыре префикса — получите десятки распределений.
rnorm(): нормальные выборки
rnorm(n, mean, sd) берёт значения из колоколообразной кривой — рабочая лошадка для моделирования данных, похожих на измерения:
Выборочные среднее и sd оказываются рядом с 100 и 15, но не точно на них: этот зазор и есть выборочный шум, сокращающийся с ростом n. Последняя строка — приём, который стоит украсть: mean() от логического вектора равно доле значений TRUE, и доля выше 130 выходит близкой к теоретической 1 - pnorm(130, 100, 15) ≈ 2.3%. Умолчания — mean = 0, sd = 1 (стандартное нормальное). Гистограмма по iq покажет знакомый колокол.
runif(), rbinom(), rpois()
Ещё три семейства закрывают большинство потребностей симуляции:
runif() распределяет значения равномерно по диапазону («uniform», а не «run if» — все хоть раз прочитывают неверно). rbinom(n, size, prob) моделирует n экспериментов по size испытаний каждый и возвращает количество успехов в каждом, так что каждое значение выше — это число орлов из 10 бросков. rpois(n, lambda) генерирует количества событий, происходящих независимо с известной средней интенсивностью: заявки в поддержку за час, опечатки на страницу.
sample(): отбор и перемешивание
Там, где функции r* выдумывают значения из распределения, sample() берёт из значений, которые у вас уже есть:
Аргумент replace объясняет всё: FALSE (по умолчанию) раздаёт карты — каждое значение может выпасть один раз, и просьба взять больше, чем есть, является ошибкой; TRUE бросает кости — каждое извлечение начинается заново. Отбор с возвращением из собственных данных — двигатель бутстрепа. Вызванная только с вектором, sample(x) возвращает случайную перестановку — идиома перемешивания.
Отбор строк датафрейма использует sample() внутри индексации строк:
sample(nrow(mtcars), 5) выбирает 5 случайных номеров строк; индексация вытягивает эти строки. Это стандартный приём для выборочной проверки большого набора данных или разделения на обучающую и тестовую выборки.
Мини-симуляция Монте-Карло
Вот ради чего собирался весь инструментарий. Вопрос: процесс даёт измерения, распределённые как N(100, 15); вы усредняете 10 из них — какова вероятность, что это среднее превысит 105? Вместо вывода формулы смоделируйте: проведите эксперимент 10 000 раз и посчитайте:
Симуляция укладывается в пару тысячных от точного значения (около 0.146). Вот Монте-Карло на одном дыхании: опишите одно испытание функцией, повторите её тысячи раз через replicate() и возьмите mean() от успехов. Точный ответ здесь существовал, потому что постановка была учебно простой, — а в момент, когда вопрос становится грязным (странные распределения, максимум коррелированных величин, игра по правилам), аналитический путь закрывается, а рецепт симуляции продолжает работать без изменений. Обратите внимание на 15 / sqrt(10) в проверке: средние колеблются меньше отдельных наблюдений — тот же закон квадратного корня, что задаёт ширину доверительных интервалов.
Годится для симуляции, не годится для секретов
Одна граница, которую нужно уважать: генератор R по умолчанию (Mersenne Twister) создан для статистического качества и скорости, а не для секретности. Его вывод детерминирован при заданном зерне, а внутреннее состояние может быть восстановлено по наблюдаемому выводу — фатальные изъяны для паролей, токенов и всего, что связано с безопасностью. Для симуляции, бутстрепа и обучения он превосходен; для криптографии используйте специализированную библиотеку (например, пакет openssl), но никогда не sample() и не runif().
Что вы уносите с собой
- Один
set.seed()в начале делает каждый «случайный» результат воспроизводимым: одно зерно — одинаковые выборки. - Префиксы d/p/q/r расшифровывают всю библиотеку распределений: случайное значение, плотность, накопленная вероятность, квантиль.
rnorm(n, mean, sd),runif(n, min, max),rbinom(n, size, prob),rpois(n, lambda)закрывают большинство потребностей симуляции.sample()берёт из ваших собственных значений —replace = TRUEдля костей, умолчание для карт, безsizeдля перемешивания;df[sample(nrow(df), k), ]отбирает строки.- Монте-Карло = функция одного испытания +
replicate()+mean()— рецепт, отвечающий на вероятностные вопросы, до которых математике добраться неудобно. - Генератор случайных чисел R предназначен для симуляции, а не для криптографии.
Дальше: отладка — что на самом деле означают сообщения об ошибках R и как читать трассировку вызовов.
Часто задаваемые вопросы
Что делает set.seed() в R?
Она фиксирует начальную точку генератора случайных чисел R, поэтому следующие за ней «случайные» выборки получаются одинаковыми при каждом запуске. Вызовите её один раз в начале любого скрипта, использующего случайность, — set.seed(42), — и ваша симуляция станет воспроизводимой: коллеги, проверяющие и вы в будущем увидите те же числа.
Как сгенерировать случайные числа в R?
Выберите распределение: rnorm(n, mean, sd) для нормальных выборок, runif(n, min, max) для равномерных, rbinom(n, size, prob) для количеств успехов, rpois(n, lambda) для количеств событий. Для отбора из уже существующих значений используйте sample(x, size).
В чём разница между rnorm, dnorm, pnorm и qnorm?
Одно распределение, четыре префикса: r берёт случайные значения, d даёт высоту кривой плотности, p даёт накопленную вероятность P(X ≤ x), а q является обратной к ней — значением на заданном процентиле. Те же четыре префикса работают для любого известного R распределения: runif/dunif/punif/qunif, rbinom/dbinom/pbinom/qbinom и так далее.
Как взять случайную выборку строк из датафрейма в R?
Проиндексируйте строки через sample(): df[sample(nrow(df), 5), ] выбирает 5 строк без возвращения. Добавьте replace = TRUE для отбора с возвращением (приём, лежащий в основе бутстрепа).