Proyecto Unidad 2: Simulación epidemiológica


Al final del proyecto, tu programa debe de tener un comportamiento como el siguiente:


$ python SimulacionEpidemiologica.py

¿Cuántas personas hay en la simulación?: 9
¿Cuántos contagiados iniciales hay?: 3
¿Cuál es el valor de beta?: 0.4
¿Cuál es el valor de gamma?: 0.15

  Día 0
  array([[1, 0, 0],
         [0, 0, 1],
         [0, 0, 1]])

  Día 1
  array([[2, 0, 0],
         [1, 1, 2],
         [0, 0, 1]])

  Día 2
  array([[2, 1, 0],
         [2, 1, 2],
         [1, 0, 2]])

  Día 3
  array([[2, 2, 0],
         [2, 2, 2],
         [1, 1, 2]])

  Día 4
  array([[2, 2, 0],
         [2, 2, 2],
         [2, 2, 2]])

  Final de la simulación en día 4.
  1 Suceptibles.
  8 Removidos.
              


Código Inicial

Descarga los archivos necesarios para comenzar este proyecto.

Descargar archivos

Inspiración

Los procesos epidemiológicos siguen un patrón de comportamiento, en el cual las personas pueden entrar en uno de varios posibles estados. El modelo que describe este comportamiento en su forma más básica se conoce como modelo SIR.

Este modelo matemático considera tres posibles estados en los que pueden encontrarse los individuos ante un proceso infeccioso. Estos tres estados corresponden con:

Estos tres estado base son los que regulan el proceso infeccioso en una población de individuos cuando se presenta un patógeno. Tómese en cuenta que esta es una clara simplificación del fenómeno epidemiológico, ya que es el modelo básico.

El modelo se puede visualizar gráficamente de la forma siguiente:

SIR Graph

Dicha visualización se puede interpretar como un grafo dirigido, o como una secuencia de pasos. Nótese que en esta figura están presentes los tres estados antes mencionados S, I y R, cada uno como un nodo. Las aristas que los conectan tienen dirección, de forma que de un estado únicamente se puede pasar al siguiente y no de forma inversa (e.g. de infectado únicamente se puede pasar a removido, no de forma inversa). Igualmente se puede notar que se agregan dos parámetros antes no mencionados β (beta) y γ (gamma), los cuales indican el peso de la arista, o interpretados de otra forma indican a qué tasa o probabilidad se pasa de un estado a otro. Estos dos valores, al ser probabilidades están acotados al rango [0, 1].

Del grafo podemos interpretar entonces que:

Supongamos que tenemos una población finita de nueve individuos, los cuales por simplicidad vamos a representar en el espacio de forma cuadrada como sigue:

SSS
SSS
SSS

Al principio todos son scueptibles a contagiarse. Para que un proceso infeccioso con el modelo SIR modifique el estado de la población es necesario contar con al menos un individuo en estado infectado, de otra forma no habría manera de contagiarse.

Supongamos ahora que uno de estos nueve individuos se infecta, ahora nuestra población queda de la siguiente forma:

SSI
SSS
SSS

en esta ocasión tenemos un caso inicial, por lo que la simulación puede comenzar. Suopongamos por simplicidad que los pasos de la simulación van a ser diarios (i.e. un paso = un día). El cuadro de arriba hace referencia al día 0, donde comienza nuestra simulación.

El siguiente paso sería simular el día 1. Para lograrlo debemos de actualizar los estados de cada uno de nuestros individuos según el modelo, del cual podemos inferir las siguientes reglas básicas:

Volviendo a nuestra simulación, para el individuo de la esquina superior izquierda actualizaríamos su estado según sus vecinos. Podemos ver que ninguno de los individuos que lo rodean está infectado, de forma que no hay posibilidad de que tenga contacto con uno. Esto conlleva que no haya forma de cambiar su estado por lo que continúa como susceptible para el siguiente paso de simulación.

SSI
SSS
SSS

Avanzamos una casilla hacia la derecha en la fila, volvemos a encontrar que el individuo se encuentra en el estado de susceptible. Sin embargo, en esta ocasión uno de los individuos a sus costados está infectado, por tanto tiene una interacción y probabilidad de contagiarse.

SSI
SSS
SSS

Para determinar si se infecta o no, se debe de lanzar una moneda cargada. Este enunciado quiere decir que, si lanzamos una moneda solo hay dos posibilidades: águila o sol, pero con la particularidad de que hay una probabilidad β que caiga sol (o 1 por ejemplo) y una probabilidad 1 - β de que caiga águila (o 0). Dependiendo del valor que caiga es la decisión que se toma, en este caso si cae sol el individuo susceptible se contagia, mientras que si cae águila el individuo susceptible sigue siendo susceptible (no se infectó).

Supongamos para nuestra simulación que la moneda cargada cayó en sol, por lo que el individuo sí se contagia. De forma que ahora nuestros individuos quedan de la siguiente forma:

SII
SSS
SSS

Ahora tenemos un nuevo infectado, por lo que el patógeno se está propagando a través de nuestra población simulada, igual que en la vida real.

De forma similar ahora pasamos a evaluar el estado de nuestro siguiente individuo, notamos que en este caso ya estaba infectado.

SSI
SSS
SSS

Probablemente una de las primeras cosas que vas a notar es que el segundo individuo de la primera fila, que en nuestro paso anterior habíamos determinado como infectado, ya no lo está. No, no es un error de dedo, esto es porque, a pesar de que ya fue determinado como infectado, al principio del día o paso de nuestra simulación estaba como susceptible, por lo que todas las interacciones de ese día con los demás fueron como susceptible, ¿o a poco creías que el patógeno iba a decidir empezar a contagiar por la esquina superior izquierda y avanzar así como lo hicimos nosotros?

Por tanto va a ser muy importante que guardes temporalmente la nueva distribución de los estados en la población para el nuevo paso de simulación, así como no perder los estados iniciales en cada uno antes de la actualización.

Habiendo mencionado eso, retomemos el proceso de actualización del individuo infectado. Para hacerlo se sigue un procedimiento similar al antes mencionado de la moneda cargada pero ahora con probabilidad γ de que el individuo modifique su estado a removido y 1 - γ la probabilidad de que permanezca infectado. Supongamos que el ejercicio de la moneda cargada apuntó a que el individuo sí pasa al estado de removido. Por lo que la población en el siguiente paso de simulación quedaría de la siguiente manera:

SIR
SSS
SSS

Una vez que se haga este proceso para cada uno de los individuos de la población, se abrá terminado el paso de simuñación y se podrá pasar al siguiente. para nuestro ejemplo supongamos que después del primer paso de simulación quedó como sigue:

SIR
SSI
SSS

Supongamos que hacemos otro paso de simulación. Ahora nuestra población podría tener la siguiente distribución:

SRR
SII
SSI

Y así sucesivamente:

IRR
IIR
SSR

¿En qué momento el modelo llega a un estado estable? Esto sucede cuando ya no hay infectados en la población, de forma que ya no pueda haber transmisiones del patógeno entre los individuos. Por tanto solo existen dos escenarios finales posibles, ¿los puedes deducir?


Proyecto

En este proyecto desarrollarás un código que lleve a cabo simulaciones con el modelo SIR como la descrita anteriormente.

Tu programa le pedirá cuatro parámetros al usuario: el tamaño de la población, el número de infectados iniciales, el valor de β como el de γ.

Una vez que haya ingresado los datos, tu código deberá de distribuir el número de casos inciales indicado a lo largo de la población y llevar a cabo la simulaciuón del proceso infeccioso hasta que haya llegado a su estado estable.

Probablemente sea más ilustrativo el fenómeno si despliegas en cada paso de simulación el estado de cada individuo en la población. Al final de la simulación deberás de informar al usuario en cuántos días o simulaciones se llegó al estado estable, así como el número de susceptibles y removidos quedaron en la población al término de la misma.


Ayudas

En la carpeta comprimida (.zip) que descargaste al principio de esta página encontrarás los códigos para comenzar con el proyecto. Esta carpeta tiene dos scripts que te ayudarán a realizarlo.

Ayudas.py

Contiene la función ObtenerNumeroEntero(pregunta) que pide al usuario un número entero imrpimiendo en pantalla el parámetro opcional pregunta. Regresa el número entero ingresado por el usuario.

Tiene la definición de la función ObtenerNumeroFlotante(pregunta, min, max) que pide un número decimal al usuario imrpimiendo pregunta que es un parámetro opcional. Cuanta con otros dos parámetros opcionales: min y max. Si no se especifica ninguno de ellos el número ingresado por el usuario puede estar en el rango (-∞, ∞), mientras que si se especifica el valor min el rango para el número ingresado por el ususario sería [min, ∞), de forma comtraria si se especifica max el rango sería (-∞, max] y por último, si ambos se especifican el rango de los posibles valores quedan acotados por [min, max]. El valor regresado por la función es un número de punto flotante o decimal ingresado por el usuario en el rango especificado.

SimulacionEpidemiologica.py

Este será tu código principal. En él se importan las funciones ObtenerNumeroEntero y ObtenerNumeroFlotante antes descritas, del código Ayudas.py. Además de que importa la librería de numpy como np.

Este código cuenta también con tres asignaciones de las variables dimension que será el número de personas que el usuario espera que haya en la simulación. iniciales que será el número de infectados iniciales en la simulación, también ingresado por el usuario. Igualmente pide al usuario que indique el valor de los parámetros β y γ los cuales se asignan a las variables beta y gamma respectivamente. Ambos parámetros están delimitados por el rango [0, 1] usando los parámetros min y max de ObtenerNumeroFlotante.

En este proyecto daremos forma cuadrada a la distribución de personas, por lo que se tomará la raíz cuadrada de dimension y se crea una tupla dimensiones = (dimension, dimension). Esta tupla será la que indique las dimensiones del cuadrado. Para hacerlo se utiliza la función zeros de numpy que creará un arreglo con las dimensiones especificadas, en nuestro caso por dimensiones, mientras que inicializa todos sus elementos en cero. Este arreglo se asigna a la variable personas.

Posteriormente se llama la función CasosIniciales que su intención es distribuir el número de casos iniciales a lo largo de la población. Hemos incluiido la definición inicial de la función, dejándote como tarea la implementación.

Por último se encuentra un ciclo while el cual tiene como propósito llevar a cabo un paso de simulación hasta que se tope con el estado estable antes mencionado, donde ya no haya infectados en la población. En cada una de sus iteraciones el ciclo llama a la función PasoSimulacion la cual ya hemos definido para tí, pero que te dejamos la tarea de implementarla.

Podrás observar que el arreglo personas es un arreglo de valores numéricos. Esto nos será de ayuda para la implementación, ya que generalmente es más sencillo trabajar con números, en lugar de caracteres o cadenas de caracteres (strings). Por tanto para este proyecto, y en particular para la implementación del arreglo personas utilizaremos el siguiente mapeo entre el estado de la persona y el número que tendrá asignado su correspondiente elemento:

Por tanto esta tabla:

SR
II
RS

Y esta otra:

02
11
20

son equivalentes. Siguiendo esta equivalencia es como funciona el ciclo while que está escrito en el código.


Especificación

Para lograr este proyecto deberás de completar las funciones CasosIniciales y PasoSimulacion definidas en SimulacionEpidemiologica.py de forma que puedan llevar llevar a cabo lo siguiente:

Nota: para la simulación considera únicamente los individuos que se encuentran a distancia uno del elemento a actualizar. Esto quiere decir que únicamente si está inmediatamente después ya sea de forma vertical, horizontal o diagonal podrá afectar al individuo a actualizar. Algo como lo siguiente:

1200
1000
2000
2000

donde el elemento a actualizar es el de color verde, y aquellos que se toman en cuenta para actualizar su estado son los marcados en gris. Toma en cuenta que, por cada infectado enntre estos individuos se debe de lanzar la moneda cargada para decidir si infectan o no al individuo en verde; de forma que para este caso se debe de lanzar una primera moneda, si con esta no se infecta el individuo, entonces se lleva a cabo la segunda. Si en ninguna de las dos sale infectado, el individuo seguirá como susceptible para el siguiente paso de simulación, de lo contario entrará al estado infectado.


Walkthrough



Resultados esperados

Tu programa deberá de llevar a cabo una simulación del modelo SIR en una población indicada por los parámetros indicados por el usuario: población, número de casos iniciales, valor de los parámetros β y γ. Deberá de imprimir el estado de la población en cada día de simulación, y al llegar al final deberá de reportar el número de días que duró la simulación, así como el número de susceptibles y removidos al final del proceso infeccioso. Deberá de mostrar un comportamiento similar al siguiente:


$ python SimulacionEpidemiologica.py

¿Cuántas personas hay en la simulación?: 4
¿Cuántos contagiados iniciales hay?: 1
¿Cuál es el valor de beta?: 0.3
¿Cuál es el valor de gamma?: 0.5

  Día 0
  array([[0, 1],
         [0, 0]])

  Día 1
  array([[1, 2],
         [0, 0]])

  Día 2
  array([[1, 2],
         [0, 0]])

  Día 3
  array([[2, 2],
         [0, 0]])

  Final de la simulación en día 3.
  2 Suceptibles.
  2 Removidos.
              

Una vez que tu programa sea capaz de simular un modelo SIR para emular un proceso infeccioso, habrás culminado con éxito tu segundo proyecto.


Solución al proyecto

Archivos con la solución al proyecto SimulacionEpidemiologica.

Descargar archivos