Вероятность программирования здоровья пациентов в R - PullRequest
0 голосов
/ 18 февраля 2020

Я собираюсь предвосхитить это тем фактом, что я начинающий R.
У меня следующая проблема:

Рассмотрим простую модель, которая прогрессирует из года в год. В первый год пусть W_i = пациент здоров, I_i = пациент болен, D_i = пациент мертв. Переходы могут быть смоделированы как набор условных вероятностей.

Пусть L = количество лет, в течение которых пациент чувствует себя хорошо.

Я придумал, что функция вероятности массы L будет P (L) = (1-p) (p) ^ {L-1}.
Данная информация состоит в том, что пациент в год 1 и учитывая их возраст и факторы риска, P (W_ {i + 1} | W_ {i}) = 0,2 для всех i

Проблема состоит в том, чтобы написать функцию в R, которая моделирует траекторию одного пациента и возвращает количество лет, в течение которых пациент здоров.

Я думал, что это можно запрограммировать в R как биномиальное распределение, используя функцию rbinom. Для одного пациента

rbinom(1, 1, 0.2)

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

Следующая проблема состоит в том, чтобы использовать R для имитации 1000 траекторий пациентов и найти среднее значение по образцу в годах. Я предполагаю, что это будет расширение предыдущей части, просто заменив 1 пациента на 1000. Однако я не могу понять, где заменить 1 на 1000: n или размер

rbinom(n, size, prob)

Это предполагает, что использование rbinom - это правильная вещь, во-первых ... Если бы я делал это на другом языке программирования (скажем, Python), я бы использовал время l oop, условное для Patient_status = W и начиная с L = 0, выполните итерацию по l oop и добавьте 1 к каждой успешной итерации. Я не уверен, что R работает так же.

1 Ответ

2 голосов
/ 18 февраля 2020

Давайте начнем с того, что делает rbinom(1, 1, 0.2): он возвращает 1 экземпляр 1 независимых бернуллиевских (то есть, 0-1) случайных величин, сложенных вместе, которые имеют вероятность 0.2 быть равной 1. Таким образом, эта строка будет выдавать только 0 (что она будет делать в 80% случаев) или 1 (что она будет делать в остальные 20% времени). Как вы заметили, это не то, что вам нужно.

Проблема здесь заключается в выборе случайной величины. Биноминальная переменная отлично подходит для чего-то вроде: «Я бросаю десять кубиков. Сколько земли на 6?» потому что он имеет следующие существенные компоненты:

  • результаты, дихотомические в успех / неудачу
  • фиксированное число (десять) испытаний
  • постоянная вероятность успеха (1 / 6)
  • независимые испытания (игральные кости не влияют друг на друга)

Ситуация, которую вы описываете, не имеет этих особенностей. Итак, что делать?


Вариант 1: Go с вашим инстинктом для while() l oop. Я предскажу это, сказав, что циклы while() не рекомендуются в R по разным причинам (главным образом, из-за неэффективности). Но, поскольку вы уже понимаете эту концепцию, давайте поработаем с ней.

one_patient <- function(){
  status <- 1                       # 1 = healthy, 0 = ill
  years <- (-1)                     # count how many years completed while healthy
  while(status == 1){
    years <- years + 1              # this line will run at least one time
    status <- rbinom(1, 1, 0.2)     # your rbinom(1, 1, 0.2) line makes an appearance!
  }
  return(years)
}

Теперь выполнение one_patient() приведет к числу лет, в течение которых пациент успешно перешел из скважины в скважину. Это будет как минимум 0, так как years начинается с -1 и увеличивается как минимум один раз. Если пациенту повезет, он может быть очень высоким, хотя, скорее всего, нет. Вы можете поэкспериментировать с этим, изменив параметр 0.2 на что-то более оптимистичное c, например 0,99, для имитации длинных периодов жизни.


Опция 2: переосмыслить случайную переменную. Я упоминал выше, что переменная не была биномиальной; на самом деле это геометрия c. Ситуация типа: «Я бросаю объявление ie, пока оно не приземлится на 6. Сколько роллов потребовалось?» является геометрией c, потому что он имеет следующие существенные компоненты:

  • результаты, дихотомические в успех / неудачу
  • постоянная вероятность успеха
  • повторные испытания, которые прекращаются при первый успех достигнут
  • независимых испытаний

Так же, как биномиальные переменные имеют полезные функции в R, такие как rbinom(), pbinom(), qbinom(), dbinom(), существует соответствующая коллекция для геометрических переменных c: rgeom(), pgeom(), qgeom(), dgeom().

Чтобы использовать rgeom(), мы должны быть осторожны с одной деталью: здесь «успех» характеризуется как пациент, заболевший , потому что именно тогда эксперимент концы. (Выше, кодируя пациента как 1, мы неявно используем обратную перспективу.) Это означает, что вероятность «успеха» равна 0,8. rgeom(1, 0.8) вернет число др aws строго до первого успеха, что эквивалентно количеству лет, в течение которых пациент прошел путь от нуля к здоровью, как указано выше. Обратите внимание, что параметр 1 относится к числу раз, когда мы хотим запустить этот эксперимент, а не к чему-то еще. Следовательно:

rgeom(1, 0.8)

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


Для нескольких пациентов вы можете либо обернуть функцию one_patient() внутри replicate(), либо просто настроить первый параметр rgeom(1, 0.8). Второй вариант - намного быстрее, хотя оба быстры, если просто имитировать 1000 пациентов.


Addendum

Доказательство того, что оба имеют одинаковый эффект:

sims1 <- replicate(10000, one_patient())
hist(sims1, breaks = seq(-0.5, max(sims1) + 0.5, by = 1))

sims2 <- rgeom(10000, 0.8)
hist(sims2, breaks = seq(-0.5, max(sims2) + 0.5, by = 1))

Доказательство того, что rgeom() быстрее:

library(microbenchmark)
microbenchmark(
  replicate(10000, one_patient()),
  rgeom(10000, 0.8)
)
#Unit: milliseconds
#                            expr     min       lq      mean   median       uq     max neval
# replicate(10000, one_patient()) 35.4520 38.77585 44.135562 43.82195 46.05920 73.5090   100
#               rgeom(10000, 0.8)  1.1978  1.22540  1.273766  1.23640  1.27485  1.9734   100
...