R Challenge

Cintia

10/10/2020

“Paradoja” del cumpleaños

Seguramente haz escuchado de la “paradoja” del cumpleaños donde se desea determinar la probabilidad de que dos personas en un salón cumplan el mismo día. Para fines de este ejercicio considera que se tienen \(n\) personas, los años bisiestos no son contados ni se admiten las personas gemelas; además de que los posibles 365 cumpleaños tienen la misma probabilidad de ocurrir.

En resumen, se tienen las siguientes expresiones para determinar la probabilidad, bajo las condiciones anteriores, de que dos personas cumplan el mismo día y de que otra persona cumpla el mismo día que tú.

\[ \mathbb{P}=\left\{ \begin{array}{cl} 1- \frac{365!}{365^{n}(365-n)!} & \mbox{si } 1 \leq n \leq 365\\ 1 & \mbox{si } n > 365 \end{array}\right. ~~~~ , ~~~~ \mathbb{P} = 1 - \left(\frac{364}{365}\right)^{n} \]

  1. Crea una función que, de acuerdo a una \(n\) válida, determine ambas probabilidades.
  2. Crea una gráfica donde se tengan la distribución de cada una de las probabilidades y determina si existe algún momento en el que hay la misma probabilidad, para una \(n\), de que dos personas cumplan el mismo día y de que otra personas cumpla el mismo día que tú.

Para facilitarnos la programación de la primer probabilidad podemos considerar lo siguiente \[\mathbb{P} = 1 - \frac{365!}{365^{n}(365-n)!} = 1- \left(\frac{365}{365} \cdots \frac{365-n+1}{365}\right)\] Entonces la función para el calculo de la primera probabilidad quedaría de la siguiente manera

Paradox1 <- function(n){
  p <- 1
  #Se realiza un ciclo for para calcular las probabilidades
  for(i in 1:n) {
    p = p * ((365 - i + 1) / 365) #Casos favorables entre casos totales
  }
  1 - p
}

La función para la segunda probabilidad sería de la siguiente manera

Paradox2 <- function(n){
  1 - ((364/365)^n)
}

Combinemos las funciones Paradox1 y Paradox2 en una sola función

Birth_Paradox <- function(n){
  uno <- Paradox1(n)
  dos <- Paradox2(n)
  
  a <- paste("En un grupo con",n,"personas:")
  b <- paste("La probabilidad de que dos personas cumplan años el mismo día es",uno)
  c <- paste("La probabilidad de que alguien cumpla años el mismo dia que tú es",dos)
  todo <- c(a,b,c)
  return(todo)
}

Probemos la función Birth_Paradox para dos grupos de personas

Birth_Paradox(70) #Para un grupo de 70 personas
## [1] "En un grupo con 70 personas:"                                                      
## [2] "La probabilidad de que dos personas cumplan años el mismo día es 0.999159575965157"
## [3] "La probabilidad de que alguien cumpla años el mismo dia que tú es 0.17472945758314"
Birth_Paradox(200) #Para un grupo de 200 personas
## [1] "En un grupo con 200 personas:"                                                      
## [2] "La probabilidad de que dos personas cumplan años el mismo día es 1"                 
## [3] "La probabilidad de que alguien cumpla años el mismo dia que tú es 0.422298043300934"

Ahora veamos si existe la posibilidad de que las funciones Paradox1 y Paradox2 converjan.

Para ello vamos a graficar ambas funciones para distintos grupos de personas.

#crearemos dos vectores vacios que almacenen las probabilidades calculadas
data1 <- c()
data2 <- c()

#hagamos el calculo de amabas probabilidades para diferentes grupos (de 1 a 2000)
for(i in 1:2000){
  data1[i] <- Paradox1(i)
  data2[i] <- Paradox2(i)
}

plot(c(0, 2000), c(0, 1), type = "n", xlab = "Número de personas",
      ylab = "Probabilidad", main = "Paradoja del cumpleños")
lines(data1, pch = 19, col = "darkorchid1")
lines(data2, pch = 19, col = "darkorchid4")
grid()
legend("bottomright", legend = c("Función 1","Función 2"), pch = c(19, 19), 
       col = c("darkorchid1","darkorchid4"))

Podemos observar que las funciones se aproximan cuando \(n = 1\) o cuando \(n \to \infty\)

Relación Fibonacci-Eigen (vectores/valores)

Existen aplicaciones muy interesantes donde se utilizan los conocidos eigen vectores/valores de una matriz. Una de ellas es la relación que tienen estos con los conocidos números de Fibonacci. Recuerda que los números de Fibonacci quedan representados por la ecuación recursiva \(F_n=F_{n−1}+F_{n−2}\) y de una manera muy sencilla se puede ver que

\[ \begin{pmatrix} F_n\\ F_{n−1} \end{pmatrix} = \begin{pmatrix} 1 & 1\\ 1 & 0 \end{pmatrix} \begin{pmatrix} F_{n−1}\\ F_{n-2} \end{pmatrix} \]

  1. Crea una función para obtener el \(n\)-ésimo número de Fibonacci.
  2. Determina mediante el uso de R el eigen valor positivo correspondiente a dicha matriz (es decir, el famoso número áureo o número de oro).
  3. Crea una gráfica, para un \(n\) que desees, donde cada punto corresponda a \((F_{n−1}, ~ F_{n−2})\) o \((F_n, ~ F_{n−1})\). Dichos puntos deben ser de color de negro.
  4. En la misma gráfica coloca la recta sobre la que pasa el eigenvector correspondiente al eigenvalor del punto 1.
  5. Elige algún punto de los graficados en el punto dos y multiplícalo por el eigen valor del punto 1 y grafícalo en color rojo ¿Qué sucedió?
  6. ¿Qué concluyes de todo esto?

La sucesión de Fibonacci es la sucesión de números: \[0, ~~~ 1, ~~~ 1, ~~~ 2, ~~~ 3, ~~~ 5, ~~~ 8, ~~~ 13, ~~~ 21, ~~~ 34, ~ \ldots\]

En donde cada número se calcula sumando los dos anteriores a él. Vamos a crear una función que calcule el los números de Fibonacci

fib_n <- function(n) {
    if(n == 0){
      return(0)
    }else if(n == 1){
      return(1)
    }else if (n == 2) {
    return(1)
    }else if(n > 2){
    return(fib_n(n - 1) + fib_n(n - 2))
    }
  }

Debemos recordar que \(n\) representa la posición que el número tiene en la serie

fib_number <- function(n){
  x <- fib_n(n)
  paste("El ", n, "° número de Fibonacci es ", x)
}

Veamos si podemos obtener las primeras 7 posiciones de los números de Fibonacci

fib_number(0)
## [1] "El  0 ° número de Fibonacci es  0"
fib_number(1)
## [1] "El  1 ° número de Fibonacci es  1"
fib_number(2)
## [1] "El  2 ° número de Fibonacci es  1"
fib_number(3)
## [1] "El  3 ° número de Fibonacci es  2"
fib_number(4)
## [1] "El  4 ° número de Fibonacci es  3"
fib_number(5)
## [1] "El  5 ° número de Fibonacci es  5"
fib_number(6)
## [1] "El  6 ° número de Fibonacci es  8"

Ahora calculemos el número áureo a partir de la siguiente matriz \[ A = \begin{pmatrix} 1 & 1\\ 1 & 0 \end{pmatrix} \]

A <- rbind(c(1,1), c(1,0)) 

eigA <- eigen(A) #La función eigen() calcula los eigenvalores y eigenvectores

eigA$values #Eigenvalores de A
## [1]  1.618034 -0.618034
oro <- eigA$values[1]

paste("El número áureo es el eigenvalor positivo de la matriz A, es decir", oro)
## [1] "El número áureo es el eigenvalor positivo de la matriz A, es decir 1.61803398874989"

Ahora vamos a crear una función que grafique \(n\) elementos de la serie de Fibonacci, los puntos tendrán coordenadas \((F_n, ~ F_{n−1})\) y deben graficarse a partir de \(n=1\) puesto que el número \(F_{0-1} = F_{-1}\) no existe.

Sobre esta misma gráfia agregaremos el eigenvector correspondiente al número de oro

grafica_fib <- function(n){
  x <- c()
  y <- c()

  for(i in 1:n){
    x[i] <- fib_n(i)
    y[i] <- fib_n(i-1) 
  }
  
  plot(x, y, xlab = expression("F"[n]), ylab = expression("F"[n-1]), 
       main = paste( n, "Números de Fibonacci y el eigenvector"), pch = 19)
  abline(a =  0, b = eigA$vectors[2,1]/eigA$vectors[1,1], col = "firebrick2")
  abline(v = (seq(0, 100, 2)), col="lightgray", lty="dotted")
  abline(h = (seq(0, 100, 2)), col="lightgray", lty="dotted")
}

Para \(n = 10\) veamos como sería nuestra grafica

grafica_fib(10)

Veamos que pasa cuando multiplicamos algún punto de los graficados anteriormente (\(m\)) por el número áureo

# n es para la cantidad de puntos a graficar
# m es para el punto a multiplicar por el número de oro
graf_newPoint <- function(n, m){ 
  x <- c()
  y <- c()
  
  for(i in 1:n){
    x[i] <- fib_n(i)
    y[i] <- fib_n(i-1)
  }
  
  point <- c(x[m], y[m])
  new_point <- point * oro
  
  plot(x, y, xlab = expression("F"[n]), ylab = expression("F"[n-1]), 
      main = paste("El movimiento del punto", m), pch = 19)
  lines(new_point[1], new_point[2], type = "p", pch = 18, col = "red")
  abline(a =  0, b = eigA$vectors[2,1]/eigA$vectors[1,1], col = "firebrick2")
  abline(v = (seq(0, 100, 2)), col="lightgray", lty="dotted")
  abline(h = (seq(0, 100, 2)), col="lightgray", lty="dotted")
}

En mi caso yo quiero graficar 10 puntos de la suceción de Fibonacci y quiero multiplicar el 9° elemento por el número de oro

graf_newPoint(10,9)

De la grafica anterior podemos concluir que el número áureo es la razón de cambio de la sucesión de Fibonacci

Iteraciones

En la mayoría de cursos que haz visto se ha tenido una gran cantidad de teoría sin ver algoritmos que te permitan comprobar dichas cosas. Vamos a arreglar un poco esto y crea alguna función o método iterativo para aproximar lo siguiente. En cada uno de los casos da un ejemplo para comprobar el funcionamiento de tu solución.

  1. Derivada. Para comprobar determina si la derivada de $2x^{2} en algún punto se aproxima con tu función.
  2. Integral. Puedes usar funciones positivas para comprobar tu función utilizando la interpretación de la integral.
  3. Perímetro de una circunferencia. Investiga un poco sobre la relación que existe entre el número de lados de un polígono regular y su perímetro, así como la longitud de los lados de un polígono inscrito en una circunferencia de radio r. Con esto tienes las bases para crear una función, que de acuerdo a un numero de lados n se vaya acercando al perímetro de una circunferencia. Al final puedes comprobar tus resultados con la formula ya conocida.

Procesamiento de textos

La idea será sencilla aunque la implementación no lo sé, por lo que podrías obtener más resultados de los que coloco aquí. De acuerdo a un archivo .txt que se te será proporcionado determinar lo siguiente:

  1. Cantidad de letras.
  2. Cantidad de vocales.
  3. Cantidad de espacios.
  4. Porcentaje que representa cada letra en el texto.

No importa si consideras a los caracteres especiales como letras o no, tampoco si haces distinción entre mayúsculas y minúsculas, ni tampoco las veces que tengas que cargar el archivo.

Para este ejercicio primero debemos cargar algunas librerias

library(tokenizers)
library(readr)
library(wordcloud)
library(dplyr)
library(readr)
library(ggplot2)
library(stringr)
library(extrafont)
library(tm)
library(RColorBrewer)

Primero debemos cargar nuestro documento, y hacerle una “limpieza” con el fin de facilitar nuestro análisis

Carga_documento <- function(documento){

  #Utiliza la función file, con el parámetro r (de "read", leer)
  leer_documento <- file(documento, open = "r")

  #Aplica la función readLines para leer las líneas del archivo, 
  #fíjate que el encoding sea UTF-8
  texto_lineas <- readLines(leer_documento, encoding = "UTF-8")

  #Junta todas las lineas (párrafos) en uno solo
  texto_completo <- paste(texto_lineas, collapse = "\n")
  
  #Retiremos los signos de puntuación
  texto_sinSignos <- removePunctuation(texto_completo)

  #Vamos a cambiar los "\n" que representan los saltos de linea por espacios en blanco
  texto_SinSaltos <- str_replace_all(texto_sinSignos, "\n", " ")

  #Vamos a eliminar los espacios en blanco múltiples
  texto_SinEspacios <- str_replace_all(texto_SinSaltos, "[\\s]+", " ")
}

Para esta actividad trabajaremos con el archivo “Romeo_and_Juliet.txt” proporcionado por el ayudante.

documento <- "Romeo_and_Juliet.txt"

Carga_documento(documento)

Para nuestro texto obtendriamos lo siguiente

* Letras

analisis_letras <- function(documento){
  texto <- Carga_documento(documento)
  
  #Para dividir el documento en caracteres
  letras_texto <- tokenize_characters(texto)
  
  #Obtén la frecuencia de las letras
  tabla_letras <- table(letras_texto[[1]])
  
  #Convierte tu tabla para las letras en un data frame
  letras_df <- data_frame(letra = names(tabla_letras), 
                          frecuencia = as.numeric(tabla_letras))
  letras_df <- arrange(letras_df, desc(frecuencia))
  
  #Para saber la cantidad total de letras del texto 
  Total_letras <- colSums(letras_df[-1], na.rm = TRUE)

  #Crea una gráfica para ver la información de mejor manera
  ggplot(data = letras_df, aes(x = letra, y = frecuencia, fill = letra)) +
    geom_bar(stat = "identity", position = "dodge") +
    labs(x = "Letras", y = "Frecuencia") +
    ggtitle(paste("Grafica de frecuencia de un texto con", Total_letras, "letras"))
}
analisis_letras(documento)

* Vocales

analisis_vocales <- function(documento){
  texto <- Carga_documento(documento)
  
  #Para dividir el documento en caracteres
  letras_texto <- tokenize_characters(texto)
  
  #Obtén la frecuencia de las letras
  tabla_letras <- table(letras_texto[[1]])
  
  #Convierte tu tabla para las letras en un data frame
  letras_df <- data_frame(letra = names(tabla_letras), 
                          frecuencia = as.numeric(tabla_letras))
  letras_df <- arrange(letras_df, desc(frecuencia))
  
  #Vamos a extraer las filas que incluyen a las vocales 
  a <- letras_df[letras_df$letra== "a",]
  e <- letras_df[letras_df$letra== "e",]
  i <- letras_df[letras_df$letra== "i",]
  o <- letras_df[letras_df$letra== "o",]
  u <- letras_df[letras_df$letra== "u",]

  vocales_df <-rbind(a, e, i, o, u)  

  #Para saber el numero total de vocales vamos a sumar los valores de la columna frecuencia
  Total_Vocales <- colSums(vocales_df[-1], na.rm = TRUE)

  #Crea una gráfica para ver la información de mejor manera
  ggplot(data = vocales_df, aes(x = letra, y = frecuencia, fill = letra)) +
    geom_bar(stat = "identity", position = "dodge") +
    labs(x = "Vocales", y = "Frecuencia") +
    ggtitle(paste("Grafica de frecuencia de un texto con", Total_Vocales, "vocales"))
}
analisis_vocales(documento)

*Espacios en blanco

analisis_espacios <- function(documento){
  texto <- Carga_documento(documento)
  
  elementos_totales <- count_characters(texto)
  
  #Para dividir el documento en caracteres
  letras_texto <- tokenize_characters(texto)
  
  #Obtén la frecuencia de las letras
  tabla_letras <- table(letras_texto[[1]])
  
  #Convierte tu tabla para las letras en un data frame
  letras_df <- data_frame(letra = names(tabla_letras), 
                          frecuencia = as.numeric(tabla_letras))
  letras_df <- arrange(letras_df, desc(frecuencia))
  
  #Para saber la cantidad total de letras del texto 
  Total_letras <- colSums(letras_df[-1], na.rm = TRUE)
  
  #Ahora vamos a hacer una resta
  cant_esp <- elementos_totales - Total_letras
  
  paste("En este texto hay", cant_esp, "espacios en blanco")
}
analisis_espacios(documento)
## [1] "En este texto hay 25636 espacios en blanco"

* Porcentaja de aparición de cada letra

porcentajeAparicion <- function(documento){
  texto <- Carga_documento(documento)
  
  #Para dividir el documento en caracteres
  letras_texto <- tokenize_characters(texto)
  
  #Obtén la frecuencia de las letras
  tabla_letras <- table(letras_texto[[1]])
  
  #Convierte tu tabla para las letras en un data frame
  letras_df <- data_frame(letra = names(tabla_letras), 
                          frecuencia = as.numeric(tabla_letras))
  letras_df <- arrange(letras_df, desc(frecuencia))
  
  #Para saber la cantidad total de letras del texto 
  Total_letras <- colSums(letras_df[-1], na.rm = TRUE)
  
  porcentaje_df <- mutate(letras_df,
                          porcentaje_aparición = (frecuencia / Total_letras)*100)
  
  #Crea una nube de palabras con la siguiente función
  set.seed(4363)
  wordcloud(words = letras_df$letra, freq = letras_df$frecuencia, 
            min.freq = 1,
          max.words=1000, random.order=FALSE, rot.per=0.35,
          colors=brewer.pal(8, "Dark2"), family = "Broadway")
  
  knitr::kable(porcentaje_df, align = c("c", "c", "c"), 
               caption = "Porcentaje que las letras representan")
}
porcentajeAparicion(documento)

Porcentaje que las letras representan
letra frecuencia porcentaje_aparición
e 12818 12.1114198
t 9709 9.1738005
o 8805 8.3196326
a 8240 7.7857777
i 6909 6.5281479
h 6787 6.4128730
s 6585 6.2220081
r 6488 6.1303551
n 6468 6.1114576
l 4975 4.7007578
d 3934 3.7171419
u 3759 3.5517887
m 3358 3.1728934
y 2623 2.4784096
w 2519 2.3801425
c 2284 2.1580966
f 2030 1.9180982
g 1838 1.7366820
b 1715 1.6204622
p 1551 1.4655026
v 1109 1.0478674
k 831 0.7851919
j 277 0.2617306
x 125 0.1181095
q 65 0.0614169
z 32 0.0302360

Teorema central del límite

Es bien conocido el teorema que abordamos en este ejercicio y sólo para recordar, si \(X_1, X_2, \ldots\) es una sucesión de variables aleatorias independientes e idénticamente distribuidas, con media \(\mu\) y varianza finita \(\sigma^{2}\), la función de distribución de la variable aleatoria \(Z\) descrita por:

\[ Z = \frac{(X_1 + \ldots + X_n) - n\mu}{\sqrt{n\sigma^{2}}} \]

tiende a la función de distribución normal estándar cuando \(n \to \infty\). Entonces, tu objetivo será crear una función que, de acuerdo a una distribución (pueden ser tantas como conozcas) que sean adaptables a las condiciones del teorema, incluyendo como parámetros de la función la media y la varianza de dicha distribución y una \(n\), se creen simulaciones de dicha distribución, al igual que la v.a. \(Z\). Finalmente se tiene que dar las gráficas de probabilidad acumulada y de densidad correspondiente (puedes guardar todo en una lista). Al final, con un \(n\) grande dado en la función, se debería poder ver una “comprobación visual de dicho teorema”.