Бесконечный цикл в игре с подбрасыванием монет

Рассмотрим следующую игру с подбрасыванием монеты:

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

Вы должны платить 1 доллар за каждый бросок монеты, и вы не можете выйти из игры во время игры.

Вы получаете 10 долларов в конце каждой игры. «Выигрыш» в игре определяется как 10, полученные в конце, за вычетом уплаченной суммы. а. Смоделируйте эту игру, чтобы оценить ожидаемые выигрыши во многих играх. б. Предположим, мы используем смещенную монету. Найдите значения P(tail), которые делают игру честной, то есть ожидаемый выигрыш равен 0 долларов.

Это вопрос, на который я должен ответить, и вот моя попытка

h <- function() {  
  A <- c("H", "T")  
  s <- sample(A,4, replace = T)  
  heads <- length(which(s= = "H"))  
  tails <- length(which(s = = "T"))  
  w <- heads - tails  
  counter <- 4  
  while (w != 4) {  
    s <- sample(A,1)  
    w <- heads - tails  
    heads <- length(which(s= = "H"))  
    tails <- length(which(s = = "T"))  
    counter <- counter +1  
  }  
  return(counter)  

}  
h()

Но я думаю, что это дало мне бесконечный цикл, может ли кто-нибудь помочь?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
481
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы пересчитываете w в каждой итерации цикла на основе текущего значения heads и tails. Но эти значения всегда будут 1 и 0 (или 0 и 1). Таким образом, w всегда либо -1, либо 1, и никогда не имеет другого значения.

Другая ошибка в вашем коде заключается в том, что вы останавливаетесь только тогда, когда впереди 4 головы. Но по правилам игра должна останавливаться и тогда, когда впереди 4 решки: имеет значение только абсолютная разница.

Логика вашего кода может быть исправлена, но будет работать гораздо более простая логика (обратите внимание, что в следующем коде используются понятные имена переменных, что делает результирующий код более читабельным):

h = function () {
    sides = c('H', 'T')
    diff = 0L
    cost = 0L
    repeat {
        cost = cost + 1L
        flip = sample(sides, 1L)
        if (flip == 'H') diff = diff + 1L
        else diff = diff - 1L
        if (abs(diff) == 4L) return(cost)
    }
}

Вы можете упростить это еще больше, потому что метки сторон монеты на самом деле не имеют значения. Все, что вам нужно, это подбрасывание монеты, которое возвращает один из двух результатов.

Мы можем реализовать это как отдельную функцию. Возвращаемое значение функции не очень важно, пока у нас есть фиксированное соглашение: оно может быть в c('H', 'T'), или c(FALSE, TRUE), или c(0L, 1L) и т. д. Для наших целей было бы удобно возвращать либо -1L, либо 1L, чтобы наша функция h могла напрямую добавлять это значение к diff:

coin_toss = function () {
    sample(c(-1L, 1L), 1L)
}

Но есть и другой способ получения подбрасывания монеты: испытание Бернулли размера 1. И использование испытания Бернулли имеет хорошее свойство: мы можем тривиально расширить нашу функцию, чтобы разрешить несправедливые (предвзятые) подбрасывания монеты. Итак, вот та же функция, но с необязательным параметром bias (по умолчанию монетка подбрасывается честно):

coin_toss = function (bias = 0.5) {
    rbinom(1L, 1L, prob = bias) * 2L - 1L
}

(rbinom(…) возвращает либо 0L, либо 1L. Чтобы преобразовать область значений в c(-1L, 1L), мы умножаем на 2 и вычитаем 1.)

Теперь давайте изменим h, чтобы использовать эту функцию:

h = function (bias = 0.5) {
    cost = 0L
    diff = 0L
    repeat {
        cost = cost + 1L
        diff = diff + coin_toss(bias)
        if (abs(diff) == 4L) return(cost)
    }
}

coin_toss() равно 0 или 1, но, в зависимости от его значения, мы либо

Я хотел бы ответить на ваши вопросы, как в части а), так и в части б). Я буду использовать свои коды, чтобы сэкономить время.

Это крутая игра, в которой программная симуляция может оказаться очень полезной. Суть игры - это «бесконечный цикл», который в конечном итоге заканчивается, когда абсолютная разница количества орлов и решек равна 4. Затем записывается выигрыш. Как упомянул Конрад Рудольф, это игра типа Бернулли. Игра моделируется с помощью кода ниже:

n_games <- 1000 # number of games to play
bias <- 0.5

game_payoff <- c()

for (i in seq_len(n_games)) {
  
  cost <- 0
  flip_record <- c()
  payoff <- c()
  
  repeat{
    cost <- cost + 1
    flip <- rbinom(1, 1, prob = bias)
    flip_record <- c(flip_record, flip)

    n_tails <- length(flip_record) - sum(flip_record) # number of 0s/tails
    n_heads <- sum(flip_record) # number of 1s/heads
    
    if (abs(n_tails - n_heads) == 4) {
      game_payoff <- c(game_payoff, 10 - cost) # record game payoff
      print(paste0("single game payoff: ", 10 - cost)) # print game payoff
      break
    }
  }
}

При большом количестве прогонов, т.е. еще один цикл над этим циклом, мы узнаем, что ожидаемое значение очень близко к -6. Таким образом, игра имеет отрицательное математическое ожидание. Из этого кода следует:

library(ggplot2)
seed <- 122334

# simulation
n_runs <- 100
n_games <- 10000
bias <- 0.5

game_payoff <- c()
expected_value_record <- c()

for (j in seq_len(n_runs)) {
  
  for (i in seq_len(n_games)) {
    
    cost <- 0
    flip_record <- c()
    payoff <- c()
    
    repeat{
      cost <- cost + 1
      flip <- rbinom(1, 1, prob = bias)
      flip_record <- c(flip_record, flip)
      # print(flip_record)
      
      n_tails <- length(flip_record) - sum(flip_record) # number of 0s/tails
      n_heads <- sum(flip_record) # number of 1s/heads
      
      if (abs(n_tails - n_heads) == 4) {
        game_payoff <- c(game_payoff, 10 - cost) # record game payoff
        print(paste0("single game payoff: ", 10 - cost))
        break
      }
    }
  }
  expected_value_record <- c(expected_value_record, mean(game_payoff))
  game_payoff <- c()
}

# plot expected value
expected_value_record <- cbind.data.frame("run" = seq_len(length(expected_value_record)), expected_value_record)

ggplot(data = expected_value_record) +
  geom_line(aes(x = run, y = expected_value_record)) +
  scale_x_continuous(breaks = c(seq(1, max(expected_value_record$run), by = 3), max(expected_value_record$run))) +
  labs(
    title = "Coin flip experiment: expected value in each run. ", 
    caption = paste0("Number of runs: ", n_runs, ". ", "Number of games in each run: ", n_games, "."), 
    x = "Run", 
    y = "Expected value") +
  geom_hline(yintercept = mean(expected_value_record$expected_value_record), size = 1.4, color = "red") +
  annotate(
    geom = "text",
    x = 0.85 * n_runs,
    y = max(expected_value_record$expected_value_record),
    label = paste0("Mean across runs: ", mean(expected_value_record$expected_value_record)),
    color = "red") +
  theme(plot.title = element_text(hjust = 0.5), plot.caption = element_text(hjust = 0.5))

Графика:

Давайте теперь посмотрим на часть б) вопроса с другой симуляцией. Цикл был завернут в функцию, которую с помощью sapply мы прогоняем последовательность вероятностей:

library(ggplot2)
seed <- 122334

# simulation function
coin_game <- function(n_runs, n_games, bias = 0.5){
  game_payoff <- c()
  expected_value_record <- c()
  
  for (j in seq_len(n_runs)) {
    
    for (i in seq_len(n_games)) {
      
      cost <- 0
      flip_record <- c()
      payoff <- c()
      
      repeat{
        cost <- cost + 1
        flip <- rbinom(1, 1, prob = bias)
        flip_record <- c(flip_record, flip)
        # print(flip_record)
        
        n_tails <- length(flip_record) - sum(flip_record) # number of 0s/tails
        n_heads <- sum(flip_record) # number of 1s/heads
        
        if (abs(n_tails - n_heads) == 4) {
          game_payoff <- c(game_payoff, 10 - cost) # record game payoff
          break
        }
      }
    }
    expected_value_record <- c(expected_value_record, mean(game_payoff))
    game_payoff <- c()
  }
  return(expected_value_record)
}

# run coin_game() on a vector of probabilities - introduce bias to find fair game conditions
n_runs = 1
n_games = 1000
expected_value_record <- sapply(seq(0.01, 0.99, by = 0.01), coin_game, n_runs = n_runs, n_games = n_games)

# plot expected value
expected_value_record <- cbind.data.frame("run" = seq_len(length(expected_value_record)), "bias" = c(seq(0.01, 0.99, by = 0.01)), expected_value_record)

ggplot(data = expected_value_record) +
  geom_line(aes(x = bias, y = expected_value_record)) +
  scale_x_continuous(breaks = c(seq(min(expected_value_record$bias), max(expected_value_record$bias), by = 0.1), max(expected_value_record$bias))) +
  scale_y_continuous(breaks = round(c(0, seq(min(expected_value_record$expected_value_record), max(expected_value_record$expected_value_record), length.out = 10)), digits = 4)) +
  labs(
    title = "Coin flip experiment: expected value for each probability level", 
    caption = paste0("Number of runs per probability level: ", n_runs, ". ", "Number of games in each run: ", n_games, "."), 
    x = "Probability of success in Bernoulli trial", 
    y = "Expected value") +
  geom_hline(yintercept = 0, size = 1.4, color = "red") +
  geom_text(aes(x = 0.1, y = 0, label = "Fair game", hjust = 1, vjust = -1), size = 4, color = "red") +
  theme(plot.title = element_text(hjust = 0.5), plot.caption = element_text(hjust = 0.5))

Графика:

Изучение фрейма данных expect_value_record показывает, что игра честна, когда значения вероятности находятся в диапазонах: 0,32–0,33 или 0,68–0,69.

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

Другие вопросы по теме

Как сделать выборку без замены, используя только количество элементов каждого класса?
Мой нечестный код подбрасывания монеты дает результаты, противоречащие теории
Метод Монте-Карло для оценки вероятности того, что сумма двух брошенных игральных костей равна 7
Самый быстрый способ подсчитать, сколько раз каждая грань N-гранного игрального кубика появляется за M бросков
Ruby - Как создать 1% шанс элемента в массиве?
Как я могу хранить вероятности с плавающей запятой в файле так точно, чтобы их сумма равнялась 1?
Как получить свертку из 3 или более непрерывных PDF-файлов, чтобы получить среднее значение PDF-файлов в Python и/или R
Как смоделировать кривые регрессии квантилей для вероятностей в зависимости от предиктора в R?
Введите оператор If с использованием вероятностей
Есть ли способ выбрать случайное количество элементов из списка с независимыми вероятностями в Python?

Похожие вопросы

Как передать именованный список аргументу точек (`...`) функции (в частности, `anova`) в R? (альтернативы do.call)
Получите пиковую скорость и возраст для конкретного субъекта при значениях пиковой скорости из линейных моделей смешанных сплайнов
Пакет R renv создает подпапку «staging» — можно ли их безопасно удалить?
Написание пользовательской функции для проверки различных свойств переменных и возврата результата в сводную таблицу
Использование шейп-файла для заполнения geom_polygon
Разделить столбцы с разделителями CSV внутри набора данных с разделителями с запятой на несколько отдельных столбцов в R
Я пытаюсь заполнить значения NA в столбце «Возраст» средним значением возраста на основе пола
Построение графика рассеяния в R
Оптимизация цикла FOR для сравнения двух кадров данных в R
Определите функцию, которая принимает 2 аргумента и случайным образом возвращает один в R