Introducción a las Redes Bayesianas#

Una Red Bayesiana es un modelo gráfico probabilístico que representa un conjunto de variables y sus dependencias condicionales mediante un grafo dirigido acíclico (DAG). Este tipo de red es útil para calcular probabilidades y hacer inferencias, especialmente en escenarios con incertidumbre.

##Conceptos Básicos Nodos: Representan variables aleatorias (pueden ser discretas o continuas).

Arcos (Flechas): Indican relaciones de dependencia condicional entre los nodos.

Distribuciones Condicionales: Cada nodo tiene una tabla de probabilidad condicional (CPT) que especifica la probabilidad de ese nodo dado sus padres.

Ejemplo: A → B → C

En este ejemplo, B depende de A, y C depende de B.

##Fórmula Básica: Descomposición de la Probabilidad Conjunta Una Red Bayesiana nos permite descomponer la probabilidad conjunta de todas las variables en función de las probabilidades condicionales:

\[ P(A, B, C) = P(A) \cdot P(B | A) \cdot P(C | B) \]

#2. Código básico para crear una red bayesiana Primero, imaginemos que queremos construir una red bayesiana con tres variables aleatorias: A, B, y C, donde A afecta a B, y B afecta a C

##I. Instalación de las librerías necesarias Primero, asegúrate de que la librería pgmpy esté instalada para trabajar con redes bayesianas.

# Instalación de librerías necesarias (solo si es necesario)
!pip install pgmpy
Collecting pgmpy
  Downloading pgmpy-0.1.26-py3-none-any.whl.metadata (9.1 kB)
Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from pgmpy) (3.4.1)
Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from pgmpy) (1.26.4)
Requirement already satisfied: scipy in /usr/local/lib/python3.10/dist-packages (from pgmpy) (1.13.1)
Requirement already satisfied: scikit-learn in /usr/local/lib/python3.10/dist-packages (from pgmpy) (1.5.2)
Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from pgmpy) (2.2.2)
Requirement already satisfied: pyparsing in /usr/local/lib/python3.10/dist-packages (from pgmpy) (3.2.0)
Requirement already satisfied: torch in /usr/local/lib/python3.10/dist-packages (from pgmpy) (2.4.1+cu121)
Requirement already satisfied: statsmodels in /usr/local/lib/python3.10/dist-packages (from pgmpy) (0.14.4)
Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from pgmpy) (4.66.5)
Requirement already satisfied: joblib in /usr/local/lib/python3.10/dist-packages (from pgmpy) (1.4.2)
Requirement already satisfied: opt-einsum in /usr/local/lib/python3.10/dist-packages (from pgmpy) (3.4.0)
Requirement already satisfied: xgboost in /usr/local/lib/python3.10/dist-packages (from pgmpy) (2.1.1)
Requirement already satisfied: google-generativeai in /usr/local/lib/python3.10/dist-packages (from pgmpy) (0.7.2)
Requirement already satisfied: google-ai-generativelanguage==0.6.6 in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (0.6.6)
Requirement already satisfied: google-api-core in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (2.19.2)
Requirement already satisfied: google-api-python-client in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (2.137.0)
Requirement already satisfied: google-auth>=2.15.0 in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (2.27.0)
Requirement already satisfied: protobuf in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (3.20.3)
Requirement already satisfied: pydantic in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (2.9.2)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from google-generativeai->pgmpy) (4.12.2)
Requirement already satisfied: proto-plus<2.0.0dev,>=1.22.3 in /usr/local/lib/python3.10/dist-packages (from google-ai-generativelanguage==0.6.6->google-generativeai->pgmpy) (1.24.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/dist-packages (from pandas->pgmpy) (2.8.2)
Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->pgmpy) (2024.2)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->pgmpy) (2024.2)
Requirement already satisfied: threadpoolctl>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from scikit-learn->pgmpy) (3.5.0)
Requirement already satisfied: patsy>=0.5.6 in /usr/local/lib/python3.10/dist-packages (from statsmodels->pgmpy) (0.5.6)
Requirement already satisfied: packaging>=21.3 in /usr/local/lib/python3.10/dist-packages (from statsmodels->pgmpy) (24.1)
Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch->pgmpy) (3.16.1)
Requirement already satisfied: sympy in /usr/local/lib/python3.10/dist-packages (from torch->pgmpy) (1.13.3)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch->pgmpy) (3.1.4)
Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch->pgmpy) (2024.6.1)
Requirement already satisfied: nvidia-nccl-cu12 in /usr/local/lib/python3.10/dist-packages (from xgboost->pgmpy) (2.23.4)
Requirement already satisfied: googleapis-common-protos<2.0.dev0,>=1.56.2 in /usr/local/lib/python3.10/dist-packages (from google-api-core->google-generativeai->pgmpy) (1.65.0)
Requirement already satisfied: requests<3.0.0.dev0,>=2.18.0 in /usr/local/lib/python3.10/dist-packages (from google-api-core->google-generativeai->pgmpy) (2.32.3)
Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (5.5.0)
Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (0.4.1)
Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.10/dist-packages (from google-auth>=2.15.0->google-generativeai->pgmpy) (4.9)
Requirement already satisfied: six in /usr/local/lib/python3.10/dist-packages (from patsy>=0.5.6->statsmodels->pgmpy) (1.16.0)
Requirement already satisfied: httplib2<1.dev0,>=0.19.0 in /usr/local/lib/python3.10/dist-packages (from google-api-python-client->google-generativeai->pgmpy) (0.22.0)
Requirement already satisfied: google-auth-httplib2<1.0.0,>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from google-api-python-client->google-generativeai->pgmpy) (0.2.0)
Requirement already satisfied: uritemplate<5,>=3.0.1 in /usr/local/lib/python3.10/dist-packages (from google-api-python-client->google-generativeai->pgmpy) (4.1.1)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch->pgmpy) (3.0.1)
Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic->google-generativeai->pgmpy) (0.7.0)
Requirement already satisfied: pydantic-core==2.23.4 in /usr/local/lib/python3.10/dist-packages (from pydantic->google-generativeai->pgmpy) (2.23.4)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy->torch->pgmpy) (1.3.0)
Requirement already satisfied: grpcio<2.0dev,>=1.33.2 in /usr/local/lib/python3.10/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.6->google-generativeai->pgmpy) (1.64.1)
Requirement already satisfied: grpcio-status<2.0.dev0,>=1.33.2 in /usr/local/lib/python3.10/dist-packages (from google-api-core[grpc]!=2.0.*,!=2.1.*,!=2.10.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,<3.0.0dev,>=1.34.1->google-ai-generativelanguage==0.6.6->google-generativeai->pgmpy) (1.48.2)
Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.10/dist-packages (from pyasn1-modules>=0.2.1->google-auth>=2.15.0->google-generativeai->pgmpy) (0.6.1)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3.0.0.dev0,>=2.18.0->google-api-core->google-generativeai->pgmpy) (2024.8.30)
Downloading pgmpy-0.1.26-py3-none-any.whl (2.0 MB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.0/2.0 MB 16.0 MB/s eta 0:00:00
?25hInstalling collected packages: pgmpy
Successfully installed pgmpy-0.1.26

##II. Importación de módulos clave Aquí importamos las herramientas necesarias de pgmpy, que es una librería diseñada para trabajar con modelos gráficos probabilísticos.

from pgmpy.models import BayesianNetwork  # Para crear la estructura de la red
from pgmpy.factors.discrete import TabularCPD  # Para definir las tablas de probabilidad condicional (CPD)
from pgmpy.inference import VariableElimination  # Para realizar inferencias en la red
  • BayesianNetwork: Este módulo se utiliza para definir la estructura del modelo bayesiano, es decir, cómo están conectadas las variables.

  • TabularCPD: Permite definir las tablas de probabilidades condicionales (CPD). Estas tablas indican cómo las probabilidades de las variables dependen de otras.

  • VariableElimination: Se usa para realizar inferencias sobre la red, es decir, responder a consultas como: «¿cuál es la probabilidad de que C sea verdadero, dado que A es verdadero?»

##III. Definición de la estructura de la red Aquí definimos cómo se conectan las variables A, B y C en la red. A es un nodo «padre» de B, y B es un nodo «padre» de C. Esto significa que las probabilidades de B dependen de A, y las de C dependen de B.

model = BayesianNetwork([('A', 'B'), ('B', 'C')])

model: Es el objeto que representa nuestra red bayesiana.

[('A', 'B'), ('B', 'C')]: Esta lista de tuplas define las conexiones o «arcos» entre los nodos (variables). Aquí se indica que A influye en B, y B influye en C.

##IV. Definición de las probabilidades condicionales (CPDs) Ahora, necesitamos definir las probabilidades asociadas a cada variable. Empezamos con A, que no tiene padres (es independiente), y luego con B y C, que dependen de otras variables.

Probabilidad de A

cpd_A = TabularCPD(variable='A', variable_card=2, values=[[0.7], [0.3]])

variable='A': Estamos definiendo la CPD para la variable A.

variable_card=2: A tiene dos posibles estados (por ejemplo, True o False).

values=[[0.7], [0.3]]: Aquí estamos diciendo que P(A=True) = 0.7 y P(A=False) = 0.3.

Probabilidad condicional de B dado A

cpd_B = TabularCPD(variable='B', variable_card=2, values=[[0.8, 0.2], [0.2, 0.8]], evidence=['A'], evidence_card=[2])

variable='B': Definimos la CPD para la variable B.

values=[[0.8, 0.2], [0.2, 0.8]]: Esta tabla representa las probabilidades condicionales P(B|A). Las columnas representan los valores que puede tomar A (True o False), y las filas las probabilidades correspondientes de B.

P(B=True | A=True) = 0.8

P(B=False | A=True) = 0.2

P(B=True | A=False) = 0.2

P(B=False | A=False) = 0.8

evidence=['A']: Esta CPD depende de A.

evidence_card=[2]: A tiene dos posibles estados.

Probabilidad condicional de C dado B.

cpd_C = TabularCPD(variable='C', variable_card=2, values=[[0.9, 0.4], [0.1, 0.6]], evidence=['B'], evidence_card=[2])

values=[[0.9, 0.4], [0.1, 0.6]]: Similar a la tabla anterior, pero ahora para C dado B.

P(C=True | B=True) = 0.9

P(C=False | B=True) = 0.1

P(C=True | B=False) = 0.4

P(C=False | B=False) = 0.6

##V. Añadir las CPDs al modelo Después de definir las tablas de probabilidades condicionales, las añadimos al modelo de la red bayesiana.

model.add_cpds(cpd_A, cpd_B, cpd_C)

Aquí estamos diciendo que el modelo debe incluir estas relaciones de probabilidades entre las variables.

##VI. Verificación de la red Es buena práctica verificar que nuestra red bayesiana esté bien definida y que las CPDs sean consistentes con la estructura.

assert model.check_model()

Si algo no está bien (por ejemplo, si una CPD no está asignada correctamente), este comando lanzará un error.

##VII. Inferencia en la red Ahora podemos realizar inferencias sobre la red, como calcular la probabilidad de que C sea verdadero, dado que A es verdadero.

infer = VariableElimination(model)
posterior_C = infer.query(variables=['C'], evidence={'A': 1})
print(posterior_C)
+------+----------+
| C    |   phi(C) |
+======+==========+
| C(0) |   0.5000 |
+------+----------+
| C(1) |   0.5000 |
+------+----------+

VariableElimination(model): Esto crea un objeto de inferencia basado en el modelo de la red bayesiana.

infer.query(variables=['C'], evidence={'A': 1}): Realiza una consulta en la red. Aquí estamos preguntando: «¿Cuál es la probabilidad de que C sea verdadero, dado que A es verdadero?»

##Ejercicio de práctica

Situación: En una red médica, A representa si una persona tiene un historial familiar de una enfermedad (A=True significa que sí). B representa si la persona tiene un síntoma importante, y C representa si finalmente la persona es diagnosticada con la enfermedad.

Asume que P(A=True) = 0.7 (es común en la población).

Si una persona tiene el historial familiar, hay un 80% de probabilidad de que desarrolle el síntoma, y solo un 20% de probabilidad si no tiene historial.

Si alguien tiene el síntoma, hay un 90% de probabilidad de que sea diagnosticado con la enfermedad.

Ahora, dado que una persona tiene un historial familiar (A=True), calcula la probabilidad de que sea diagnosticada con la enfermedad (C=True).

# 1. Definir la estructura de la red bayesiana
# A -> B -> C, es decir, A afecta a B y B afecta a C
model = ____________

# 2. Definir las tablas de probabilidad condicional (CPDs)
# CPD para A (historial familiar de la enfermedad)
cpd_A = ___________
# P(A=True) = 0.7 y P(A=False) = 0.3

# CPD para B dado A (presencia del síntoma dado el historial familiar)
cpd_B = ___________
                   values=[[0.8, 0.2], [0.2, 0.8]],
                   evidence=['A'], evidence_card=[2])
# P(B=True | A=True) = 0.8, P(B=False | A=True) = 0.2
# P(B=True | A=False) = 0.2, P(B=False | A=False) = 0.8

# CPD para C dado B (diagnóstico de la enfermedad dado el síntoma)
cpd_C = TabularCPD(variable='C', variable_card=2,
                   __________________________
                   evidence=['B'], evidence_card=[2])
# P(C=True | B=True) = 0.9, P(C=False | B=True) = 0.1
# P(C=True | B=False) = 0.4, P(C=False | B=False) = 0.6

# 3. Añadir las CPDs al modelo
__________(cpd_A, cpd_B, cpd_C)

# 4. Verificar que el modelo sea válido
assert model.check_model()

# 5. Realizar inferencia en la red
infer = ______________

# 6. Consultar la probabilidad de que C sea verdadero dado que A es verdadero (historial familiar)
________ = infer.query(variables=['C'], evidence={'A': 1})
print(posterior_C)

# 7. Adicionalmente, consultar la probabilidad de que C sea verdadero dado que A y B son verdaderos
posterior_C_given_A_and_B = _________________
print(_____________)
+------+----------+
| C    |   phi(C) |
+======+==========+
| C(0) |   0.5000 |
+------+----------+
| C(1) |   0.5000 |
+------+----------+
+------+----------+
| C    |   phi(C) |
+======+==========+
| C(0) |   0.4000 |
+------+----------+
| C(1) |   0.6000 |
+------+----------+

#3. Ejemplo Explicativo: Red Simple (A → B → C) Este es un ejemplo básico de una red bayesiana con tres variables que dependen unas de otras de manera condicional.

  1. Variable A:

  • A puede tomar dos valores:

    • 1 (verdadero), con una probabilidad de 0.7.

    • 0 (falso), con una probabilidad de 0.3.

Esto significa que, sin ninguna información adicional, hay un 70% de probabilidad de que A sea 1 y un 30% de que sea 0.

  1. Variable B (depende de A):

  • Si A = 1 (es decir, A es verdadero), B tiene una probabilidad de 0.8 de ser 1 y una probabilidad de 0.2 de ser 0.

    • En otras palabras, si hay historial familiar (A = 1), hay un 80% de probabilidad de que se presente el síntoma B.

  • Si A = 0 (es decir, A es falso), B tiene una probabilidad de 0.2 de ser 1 y una probabilidad de 0.8 de ser 0.

    • Si no hay historial familiar (A = 0), solo hay un 20% de probabilidad de que el síntoma B esté presente.

  1. Variable C (depende de B):

  • Si B = 1 (B es verdadero, es decir, se presenta el síntoma), entonces C tiene una probabilidad de 0.9 de ser 1.

    • Es decir, si se presenta el síntoma B, hay un 90% de probabilidad de que la persona sea diagnosticada con la enfermedad.

  • Si B = 0 (B es falso, no se presenta el síntoma), C tiene una probabilidad de 0.4 de ser 1 y 0.6 de ser 0.

    • Si no se presenta el síntoma, la probabilidad de que la persona sea diagnosticada es más baja (40%).

###Resumen de las relaciones entre las variables:

  1. A tiene una probabilidad fija de ser verdadero o falso.

  2. B depende de A: si A es verdadero, es más probable que B también lo sea.

  3. C depende de B: si B es verdadero, es mucho más probable que C también sea verdadero.

Este tipo de estructura refleja cómo en la vida real ciertos eventos pueden depender de otros. Por ejemplo, en el contexto médico:

  • A podría ser un factor genético, como tener familiares con una enfermedad.

  • B podría representar la presencia de un síntoma importante.

  • C podría ser el diagnóstico de la enfermedad, el cual depende tanto de los síntomas como de los antecedentes familiares.

La red nos ayuda a modelar la relación entre estos factores y a calcular probabilidades conjuntas, es decir, a conocer la probabilidad de un resultado final dado cierto historial o síntoma.

#4: Inferencia Básica en Redes Bayesianas ##¿Qué es la inferencia? La inferencia en una red bayesiana nos permite responder preguntas del tipo «¿Cuál es la probabilidad de que ocurra X dado que ya sabemos Y?».

Por ejemplo:

Si sabemos que la variable A (historial familiar) es 1 (verdadero), ¿cuál es la probabilidad de que C (la enfermedad) también sea 1?

##Ejemplo de inferencia:

Volvamos a nuestra Red Simple (A → B → C) de la sección anterior, y enfoquémonos en calcular probabilidades cuando tenemos cierta información conocida, es decir, cuando tenemos evidencia.

###Paso 1: Configuración de las probabilidades Recordemos las dependencias entre las variables:

  • P(A): la probabilidad de A es 0.7 (A=1) y 0.3 (A=0).

  • P(B|A): depende de A.

  • P(C|B): depende de B.

Queremos calcular la probabilidad de C dado que conocemos el valor de A.

###Paso 2: Ejemplo de inferencia Supongamos que ya sabemos que A = 1 (historial familiar positivo), queremos calcular la probabilidad de que C = 1 (la enfermedad), tomando en cuenta la dependencia entre A, B y C.

\[P(C=1 | A=1) = P(A=1) \cdot P(B=1 | A=1) \cdot P(C=1 | B=1)\]

La probabilidad conjunta es:

  • P(A=1) = 0.7

  • P(B=1 | A=1) = 0.8

  • P(C=1 | B=1) = 0.9

\[P(C=1 | A=1) = 0.7 \cdot 0.8 \cdot 0.9 = 0.504\]

Entonces, si A = 1, la probabilidad de que C=1 es 0.504 (o 50.4%).

# Definimos las probabilidades base
P_A = 0.7  # Probabilidad de A=1
P_B_given_A = 0.8  # Probabilidad de B=1 dado A=1
P_C_given_B = 0.9  # Probabilidad de C=1 dado B=1

# Calcular la probabilidad conjunta de C=1 dado A=1
P_C_given_A = P_A * P_B_given_A * P_C_given_B

print(f"La probabilidad de que C=1 dado que A=1 es: {P_C_given_A:.3f}")
La probabilidad de que C=1 dado que A=1 es: 0.504

El cálculo de la probabilidad conjunta se realiza multiplicando las probabilidades, porque asumimos que la relación entre las variables sigue el principio de la regla de la cadena de probabilidad.

##Ejercicio de práctica: Ahora, cambia la evidencia:

Si ahora A = 0, ¿cuál es la probabilidad de que C = 1? Modifica las probabilidades en el código para calcular esto.

#5. Ejercicios para practicar ##Ejercicio 1: Inferencia Básica en Redes Bayesianas Contexto: Imagina que estás trabajando en el área de medicina y quieres calcular la probabilidad de que un paciente tenga una enfermedad cardíaca \( C \) dado que tiene antecedentes familiares \( A \) y ha sido diagnosticado con hipertensión \( B \).

La relación entre estas variables sigue el siguiente esquema:

\( A \ (\text{Antecedentes Familiares}) \to B \ (\text{Hipertensión}) \to C \ (\text{Enfermedad Cardíaca}) \)

Probabilidades dadas: \( P(A = 1) = 0.4, \quad P(A = 0) = 0.6 \)

\( P(B = 1 \mid A = 1) = 0.7, \quad P(B = 1 \mid A = 0) = 0.2 \)

\( P(C = 1 \mid B = 1) = 0.9, \quad P(C = 1 \mid B = 0) = 0.3 \)

Objetivo: Los estudiantes deben calcular la probabilidad conjunta de que el paciente tenga antecedentes familiares \( A = 1 \), hipertensión \( B = 1 \), y la enfermedad cardíaca \( C = 1 \).

\( P(C = 1, B = 1, A = 1) \)

# Definir las probabilidades
P_A = ____  # P(A=1)
P_B_given_A1 = ____  # P(B=1 | A=1)
P_B_given_A0 = ____  # P(B=1 | A=0)
P_C_given_B1 = ____  # P(C=1 | B=1)
P_C_given_B0 = ____  # P(C=1 | B=0)

# Calcular la probabilidad conjunta P(C=1 | A=1, B=1)
P_A_1_B_1_C_1 = ____ * ____ * ____  # P(A=1) * P(B=1|A=1) * P(C=1|B=1)

print(f"La probabilidad conjunta de que el paciente tenga antecedentes, hipertensión y la enfermedad es: {P_A_1_B_1_C_1:.3f}")

##Ejercicio 2: Creación Básica de una Red Bayesiana Contexto: En el área de la ciberseguridad, estamos interesados en modelar la probabilidad de que un sistema sufra un ataque exitoso \( A \) dado que tiene vulnerabilidades \( V \) y que un atacante está realizando un escaneo \( S \).

El esquema de la red es el siguiente:

\( V \ (\text{Vulnerabilidad}) \to S \ (\text{Escaneo}) \to A \ (\text{Ataque}) \)

Probabilidades dadas: \( P(V = 1) = 0.5 \)

\( P(S = 1 \mid V = 1) = 0.8, \quad P(S = 1 \mid V = 0) = 0.3 \)

\( P(A = 1 \mid S = 1) = 0.9, \quad P(A = 1 \mid S = 0) = 0.2 \)

Objetivo: Crear una red bayesiana simple usando pgmpy que modele este sistema de ciberseguridad, y luego calcular la probabilidad de que ocurra un ataque exitoso \( A = 1 \), dado que hay vulnerabilidades \( V = 1 \) y un escaneo \( S = 1 \).

\( P(A = 1 \mid V = 1, S = 1) \)

from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination

# Crear la red bayesiana
modelo = BayesianNetwork([('V', 'S'), ('S', 'A')])

# Definir las CPDs (Tablas de Probabilidades Condicionales)
cpd_V = TabularCPD(variable='V', variable_card=2, values=[[____], [____]])  # P(V)
cpd_S = TabularCPD(variable='S', variable_card=2,
                   values=[[____, ____], [____, ____]],  # P(S | V)
                   evidence=['V'], evidence_card=[2])
cpd_A = TabularCPD(variable='A', variable_card=2,
                   values=[[____, ____], [____, ____]],  # P(A | S)
                   evidence=['S'], evidence_card=[2])

# Añadir las CPDs al modelo
modelo.add_cpds(cpd_V, cpd_S, cpd_A)

# Comprobar la consistencia del modelo
assert modelo.check_model()

# Inferencia
inferencia = VariableElimination(modelo)

# Calcular P(A = 1 | V = 1, S = 1)
resultado = inferencia.query(variables=['A'], evidence={'V': 1, 'S': 1})
print(resultado)

#6. Conclusión En este notebook, exploramos las redes bayesianas desde sus fundamentos, abarcando su creación, inferencia y aplicación en contextos médicos y de ciberseguridad. A través de ejemplos prácticos y ejercicios guiados, aprendimos a modelar sistemas complejos utilizando pgmpy y calculamos probabilidades conjuntas y condicionales. Este enfoque proporciona una poderosa herramienta para modelar incertidumbre y dependencia entre variables, algo esencial en áreas como la medicina, las ciencias de la computación, y otras disciplinas. Con una base sólida en redes bayesianas, podrás ampliar tus análisis hacia problemas más complejos y multidimensionales.