# Generar n coordenadas aleatorias (x, y) dentro del cuadrado (0, 1)
generar_coordenadas <- function(n) {
  data.frame(x = runif(n, 0, 1), y = runif(n, 0, 1))
}


# Crear una simulación de Pi, dado un numero de coordenadas
simular_pi <- function(n, imprimir_valores) {
  coordenadas <- generar_coordenadas(n)

  # Calcular la distancia al centro (0.5, 0.5) para cada punto
  distancia <- sqrt((coordenadas$x - 0.5)^2 + (coordenadas$y - 0.5)^2)

  # Contar cuántos puntos están dentro del círculo (distancia < 0.5)
  dentro <- sum(distancia < 0.5)

  # Calcular la estimación de π
  estimacion_pi <- 4 * dentro / n

  # Mostrar la cantidad de puntos dentro del círculo y la estimación de π
  if (imprimir_valores == TRUE){
    cat(paste("Puntos dentro del círculo:", dentro, "\n"))
    cat(paste("Estimación de π:", estimacion_pi, "\n"))
  }

  coordenadas$dentro <- dentro
  coordenadas$estimacion_pi <- estimacion_pi
  coordenadas
}

# crear n simulaciones de pi

simular_pi_multiple <- function(n, m) {
  dentro <- c()
  estimacion_pi <- c()
  error <- c()

  for(i in 1:n){
    simular <- simular_pi(m, FALSE)
    dentro <- append(dentro, simular$dentro[1])
    estimacion_pi <- append(estimacion_pi, simular$estimacion_pi[1])
    error <- append(error, abs(pi - simular$estimacion_pi[1]))
  }

  data.frame(dentro = dentro, estimacion_pi = estimacion_pi, error = error)
}

# Crear grafica de dispersión con el circulo

crear_grafico_punto <- function(dataframe){
  ggplot(dataframe, aes(x = !!sym("x"), y = !!sym("y"))) +
    geom_point(size = 3) +
    geom_circle(aes(x0 = 0.5, y0 = 0.5, r = 0.5)) +
    labs(title = "Gráfico de dispersión", x = "Etiqueta eje X", y = "Etiqueta eje Y")
}

La constante matemática pi (π)

La constante matemática pi (π), que representa la razón entre la circunferencia de un círculo y su diámetro, es un valor fundamental que sustenta numerosas disciplinas científicas e ingenieriles. Si bien calcular su valor exacto puede implicar enfoques matemáticos complejos como series infinitas, este artículo explora un método divertido e intuitivo para estimar pi: la simulación de Monte Carlo.

Simulación de Monte Carlo

La simulación de Monte Carlo, que lleva el nombre de los glamorosos casinos de Mónaco, es una técnica poderosa que aprovecha el poder de la aleatoriedad. Al muestrear repetidamente de una distribución de probabilidad bien definida, podemos aproximar soluciones a problemas que involucran cálculos complejos o dependen de variables aleatorias. En nuestro caso, utilizaremos la simulación de Monte Carlo para estimar el área de un círculo inscrito en un cuadrado dispersando estratégicamente una gran cantidad de puntos dentro del cuadrado. Cuantos más puntos dispersemos, más precisa será nuestra estimación del área del círculo.

Configuración del problema

Imagine un cuadrado con un área de 1 unidad cuadrada. Este cuadrado acuna un círculo centrado perfectamente en su punto medio. Si bien el área del círculo no se da directamente, tiene una conexión secreta con pi (π). La clave radica en la razón entre el área del círculo y el área del cuadrado, que es exactamente igual a π/4.

Desglosemos esta conexión a travez de una breve expresión matématica:

Área del cuadrado (A_square) = 1 (dada) Área del círculo (A_circle) = π/4 (desconocida) Por lo tanto, π/4 = A_circle / A_square.

Ahora, supongamos que distribuimos aleatoriamente una gran cantidad de puntos dentro de los confines del cuadrado. La probabilidad de que un punto en particular aterrice dentro del círculo es directamente proporcional a la razón entre el área del círculo y el área del cuadrado, que, como sabemos, es π/4.

crear_grafico_punto(generar_coordenadas(10))

Método de simulación

Podemos aprovechar este concepto de probabilidad para estimar pi. A continuación se muestra un desglose detallado de los pasos involucrados:

Paso 1: Generación de coordenadas

Lenguaje de programación: Usaremos el lenguaje de programación R para esta simulación.

Número de puntos: Definimos la cantidad de puntos que queremos simular (denotados por n). Un n más alto generalmente conduce a una estimación más precisa. Cuantos más puntos dispersemos dentro del cuadrado, más precisa será nuestra aproximación del área del círculo.

Coordenadas aleatorias: Usamos la función runif(n) en R para generar n coordenadas x e y aleatorias para cada punto. Estas coordenadas se distribuirán uniformemente entre 0 y 1, representando los límites del cuadrado.

cat("Grafico de muestra para 10 coordenadas generadas aleatoriamente:")
## Grafico de muestra para 10 coordenadas generadas aleatoriamente:
crear_grafico_punto(generar_coordenadas(10))

Paso 2: Cálculo de la distancia

Objetivo: Para cada punto, necesitamos determinar si cae dentro del círculo. Fórmula de la distancia: La fórmula de la distancia estándar calcula la distancia entre dos puntos usando sus coordenadas x e y.

Distancia al centro del circulo: Esta distancia al cuadrado se obtiene utilizando la fórmula: distancia al cuadrado y luego aplicando la raiz cuadrada = ((x - 0.5)2 + (y - 0.5)2 )(1/2)

Paso 3: Determinación interior/exterior

Comparación: Comparamos la distancia al centro del circulo de cada punto (calculada en el paso 2.3) con el radio del círculo (que es 0.5).

cat("Calculo de los puntos dentro del circulo para una muestra de 10 pares de coordenadas generadas\n\n")
## Calculo de los puntos dentro del circulo para una muestra de 10 pares de coordenadas generadas
crear_grafico_punto(simular_pi(10, TRUE))
## Puntos dentro del círculo: 10 
## Estimación de π: 4

Paso 4: Estimación de Pi

Contar puntos interiores: Contamos la cantidad de puntos que aterrizaron dentro del círculo usando la función sum en R. Conexión de probabilidad: Dado que la probabilidad de que un punto esté dentro del círculo es π/4, la fracción estimada de puntos dentro del círculo representa una aproximación de π/4.

Estimación final: Para obtener la estimación final de pi (π), empleamos la siguiente expresión:

π = 4 * (Puntos dentro del circulo)/(Puntos totales)

Esta ecuación ilustra lo comentado al inicio, la proporcionalidad entre la cantidad de puntos dentro del circulo y los puntos totales deberia ser igual a la proporcion entre el area del cuadrado y del circulo.

Paso 5: Simulación de Pi empleando diferentes tamaños de coordenadas generadas

Sabemos que entre más puntos se generen en el cuadrado, más preciso será nuestra estimación de Pi, teniendo esto en cuenta se estimará el valor de Pi con diferentes tamaños de muestra, empezando desde 10 pares de cordenadas, luego 100 pares de coordenadas, 1000 pares de coordenadas, asi sucesivamente aumentando en potencia de 10, hasta un total de coordenadas de 10’000.000 de coordenadas.

Paso 6: Simulación de Pi repetidamente para estimar un promedio adecuado

Dado que cada vez que generamos coordenadas nuestra estimación de Pi cambiará, es decir, si simulo 100 veces el valor de pi generando 1000 coordenadas, en cada generación obtendremos un resultado diferente, por lo anterior, para ir más allá en nuestro analisis, simularemos 10 veces la estimación de pi, para cada tamaño de muestro.

Estimaremos el valor de pi 10 veces para los diferentes tamaños del grupo de coordenadas y obtendremos un promedio del valor, es decir, generaremos 1000 coordenadas y obtendremos el valor de Pi, luego, volveremos a generar otras 1000 coordenadas y se estimara nuevamente pi hasta 10 intentos, esto se realizará para todos los tamaños de grupos de coordenadas.

Resultados

Para nuestra primer estimación de pi con 10 coordenadas obtenemos los siguientes resultados:

simulacion_1 <- simular_pi(10, TRUE)
## Puntos dentro del círculo: 8 
## Estimación de π: 3.2
crear_grafico_punto(simulacion_1)

cat(paste("\n La grafica anterior nos muestra que", simulacion_1$dentro[1], "puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de", simulacion_1$estimacion_pi[1]))
## 
##  La grafica anterior nos muestra que 8 puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de 3.2

Los resultados nos indican que para un numero tan pequeño de coordenadas la estimación de pi, dependiendo de la aleatoriedad de la generación puede estimar un valor muy alejado, esta primer estimación resulta muy interesante estudiarla ya que si caen 8 puntos en el circulo, se obtendrá una estimación de 3.2, lo cual es bastante precisa para la poca cantidad de puntos.

Estimación de Pi con 100 coordenadas

Ahora estimaremos el valor de pi empleando un numero un poco más grande de coordenadas:

simulacion_2 <- simular_pi(100, TRUE)
## Puntos dentro del círculo: 80 
## Estimación de π: 3.2
crear_grafico_punto(simulacion_2)

cat(paste("\n La siguiente grafica nos muestra que", simulacion_2$dentro[1], "puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de", simulacion_2$estimacion_pi[1]))
## 
##  La siguiente grafica nos muestra que 80 puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de 3.2

La estimación con 100 coordenadas dan resultados muy similares a los vistos usando 10 coordenadas, pero nos brinda una mayor precisión y estabilidad en cuanto a la aleatoriedad.

Estimación de Pi con 1000 coordenadas

simulacion_3 <- simular_pi(1000, TRUE)
## Puntos dentro del círculo: 801 
## Estimación de π: 3.204
crear_grafico_punto(simulacion_3)

cat(paste("\n La siguiente grafica nos muestra que", simulacion_3$dentro[1], "puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de", simulacion_3$estimacion_pi[1]))
## 
##  La siguiente grafica nos muestra que 801 puntos se generarón dentro del circulo, lo que nos permite estimar un valor de pi de 3.204

La simulación con 1000 coordenadas no solo nos permite una mayor estabilidad ante la aleatoriedad, si no que a su vez mejora la exactitud y la precisión y nos permite estimar a un mayor nivel de numeros decimales.

Simulación con 10.000 coordenadas

simulacion <- simular_pi(10000, TRUE)
## Puntos dentro del círculo: 7856 
## Estimación de π: 3.1424

Simulación con 100.000 coordenadas

simulacion <- simular_pi(100000, TRUE)
## Puntos dentro del círculo: 78457 
## Estimación de π: 3.13828

Simulación con 1’000.000 coordenadas

simulacion <- simular_pi(1000000, TRUE)
## Puntos dentro del círculo: 785708 
## Estimación de π: 3.142832

Las grandes simulaciones de más de 10000 coordenadas nos brindan mejores resultados en las estimaciones, con una mejor exactitud y precisión.

Si bien estos resultados son muy buenos, sufren debido a la aleatoriedad de la generación de las coordenadas, si se genera un grupo de coordenadas con menos o más puntos dentro del circulo de los que deberia haber, esto disminuirá la exactitud, por lo que resulta de importancia general, simular varias veces con el mismo numero de coordenadas.

Simulación repetida del valor de Pi

Estimar repetidamente el valor de Pi para cada numero de coordenadas nos permitirá definir un valor menos volatil y más estable, para obtener mejores resultados, a continuación presentamos los valores obtenidos.

10 Simulaciones con 10 coordenadas

simulacion_multiple_1 <- simular_pi_multiple(10, 10)

kable(simulacion_multiple_1)
dentro estimacion_pi error
9 3.6 0.4584073
5 2.0 1.1415927
7 2.8 0.3415927
6 2.4 0.7415927
10 4.0 0.8584073
9 3.6 0.4584073
8 3.2 0.0584073
5 2.0 1.1415927
8 3.2 0.0584073
5 2.0 1.1415927
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_1$estimacion_pi)))
## 
## 
## Estimación Promedio: 2.88
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_1$error)))
## 
## 
## Error Promedio: 0.64
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_1$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 20.3718327157626 %

Los resultados anteriores muestran lo dispersa que puede llegar a ser esta estimació con un numero tan pequeño de coordenadas, pero el resultado promedio demuestra ser mucho más aproximado.

10 Simulaciones con 100 coordenadas

simulacion_multiple_2 <- simular_pi_multiple(10, 100)

kable(simulacion_multiple_2)
dentro estimacion_pi error
82 3.28 0.1384073
79 3.16 0.0184073
74 2.96 0.1815927
81 3.24 0.0984073
79 3.16 0.0184073
75 3.00 0.1415927
83 3.32 0.1784073
82 3.28 0.1384073
85 3.40 0.2584073
85 3.40 0.2584073
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_2$estimacion_pi)))
## 
## 
## Estimación Promedio: 3.22
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_2$error)))
## 
## 
## Error Promedio: 0.143044407846124
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_2$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 4.55324491807275 %

10 Simulaciones de 1000 coordenadas

simulacion_multiple_3 <- simular_pi_multiple(10, 1000)

kable(simulacion_multiple_3)
dentro estimacion_pi error
768 3.072 0.0695927
793 3.172 0.0304073
787 3.148 0.0064073
783 3.132 0.0095927
802 3.208 0.0664073
765 3.060 0.0815927
812 3.248 0.1064073
783 3.132 0.0095927
789 3.156 0.0144073
796 3.184 0.0424073
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_3$estimacion_pi)))
## 
## 
## Estimación Promedio: 3.1512
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_3$error)))
## 
## 
## Error Promedio: 0.0436814692820414
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_3$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 1.39042435155074 %

10 Simulaciones de 10.000 coordenadas

simulacion_multiple_4 <- simular_pi_multiple(10, 10000)

kable(simulacion_multiple_4)
dentro estimacion_pi error
7923 3.1692 0.0276073
7905 3.1620 0.0204073
7873 3.1492 0.0076073
7893 3.1572 0.0156073
7812 3.1248 0.0167927
7898 3.1592 0.0176073
7808 3.1232 0.0183927
7781 3.1124 0.0291927
7930 3.1720 0.0304073
7861 3.1444 0.0028073
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_4$estimacion_pi)))
## 
## 
## Estimación Promedio: 3.14736
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_4$error)))
## 
## 
## Error Promedio: 0.0186429385640827
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_4$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 0.593423165246457 %

10 Simulaciones de 100.000 coordenadas

simulacion_multiple_5 <- simular_pi_multiple(10, 100000)

kable(simulacion_multiple_5)
dentro estimacion_pi error
78434 3.13736 0.0042327
78361 3.13444 0.0071527
78677 3.14708 0.0054873
78595 3.14380 0.0022073
78477 3.13908 0.0025127
78653 3.14612 0.0045273
78616 3.14464 0.0030473
78578 3.14312 0.0015273
78616 3.14464 0.0030473
78414 3.13656 0.0050327
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_5$estimacion_pi)))
## 
## 
## Estimación Promedio: 3.141684
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_5$error)))
## 
## 
## Error Promedio: 0.00387746928204136
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_5$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 0.123423680584773 %

10 Simulaciones de 1’000.0000 de coordenadas

simulacion_multiple_6 <- simular_pi_multiple(10, 1000000)

kable(simulacion_multiple_6)
dentro estimacion_pi error
784894 3.139576 0.0020167
785568 3.142272 0.0006793
785649 3.142596 0.0010033
785370 3.141480 0.0001127
785592 3.142368 0.0007753
785301 3.141204 0.0003887
785794 3.143176 0.0015833
785484 3.141936 0.0003433
785939 3.143756 0.0021633
785417 3.141668 0.0000753
cat(paste("\n\nEstimación Promedio:", mean(simulacion_multiple_6$estimacion_pi)))
## 
## 
## Estimación Promedio: 3.1420032
cat(paste("\n\nError Promedio:", mean(simulacion_multiple_6$error)))
## 
## 
## Error Promedio: 0.000914138564082778
cat(paste("\n\nError Procentual:", (mean(simulacion_multiple_6$error)/pi)*100, "%"))
## 
## 
## Error Procentual: 0.0290979342289403 %
categoria <- c("Estimación 10 Coord", "Estimación 100 Coord", "Estimación 1000 Coord", "Estimacion 10.000 Coord", "Estimación 100.000 Coord", "Estimación 1'000.000 Coord")
estimaciones <- c(mean(simulacion_multiple_1$estimacion_pi), mean(simulacion_multiple_2$estimacion_pi), mean(simulacion_multiple_3$estimacion_pi), mean(simulacion_multiple_4$estimacion_pi), mean(simulacion_multiple_5$estimacion_pi), mean(simulacion_multiple_6$estimacion_pi))
errores <- c(mean(simulacion_multiple_1$error), mean(simulacion_multiple_2$error), mean(simulacion_multiple_3$error), mean(simulacion_multiple_4$error), mean(simulacion_multiple_5$error), mean(simulacion_multiple_6$error))
kable(data.frame(categoria = categoria, estimacion = estimaciones, error = errores))
categoria estimacion error
Estimación 10 Coord 2.880000 0.6400000
Estimación 100 Coord 3.220000 0.1430444
Estimación 1000 Coord 3.151200 0.0436815
Estimacion 10.000 Coord 3.147360 0.0186429
Estimación 100.000 Coord 3.141684 0.0038775
Estimación 1’000.000 Coord 3.142003 0.0009141
categoria <- c("Simulación 1", "Simulación 2", "Simulación 3", "Simulación 4", "Simulación 5", "Simulación 6")
estimaciones <- c(mean(simulacion_multiple_1$estimacion_pi), mean(simulacion_multiple_2$estimacion_pi), mean(simulacion_multiple_3$estimacion_pi), mean(simulacion_multiple_4$estimacion_pi), mean(simulacion_multiple_5$estimacion_pi), mean(simulacion_multiple_6$estimacion_pi))
errores <- c(mean(simulacion_multiple_1$error), mean(simulacion_multiple_2$error), mean(simulacion_multiple_3$error), mean(simulacion_multiple_4$error), mean(simulacion_multiple_5$error), mean(simulacion_multiple_6$error))
resultado_final <- data.frame(categoria = categoria, estimacion = estimaciones, error = errores)
ggplot(resultado_final, aes(x = categoria, y = errores, group = 1)) +
  geom_line()+
  theme_minimal()+
  geom_text(aes(label = round(errores, 4)), vjust = 1.5)+
  labs(title = "Error medio en cada simulación")+
  theme(plot.title = element_text(size = 16, hjust = 0.5))

Esta estimación de Pi mediante el uso de la probabilidad y la aleatoriedas es una manera muy divertida de calcular este valor, te permite visualizar la aleatoriedad como algo muy diferente que puede ser aplicado para muchas cosas, aunque esto requiere de un pensamiento lateral y una creatividad, siempre podemos encontrar nuevos usos y utilidades para la estadistica.

Estas aproximaciones son muy buenas, a medida que nuestro numero de puntos incrementa en nuestro plano, la aproximación será mucho más exacta y precisa, demostrando que la cantidad de individuos en un analisis es muy valiosa para una estimación más acertada.