Bajo la colaboración y supervisión de la profesora Natalia Henríquez,
pretendo escribir una guía mucho más práctica que teórica, utilizando un
lenguaje amigable e informal, en la cual aplicaré los conceptos
estadísticos y lo que he ido aprendiendo sobre R para
realizar análisis básico de datos, crear ejemplos, y resolver
ejercicios. El siguiente trabajo no tiene por intención ser un apunte de
estadística o un manual de R.
Añadidos de la nueva versión
Traspasé todo lo del documento Latex a R Markdown, que está
basado en HTML creo. Como es un lenguaje creado para escribir texto de
R, todo es mucho más sencillo y estético
que en Latex. Lo recomiendo. Sigo aprendiendo a usarlo pero lo básico lo
entendí en un fin de semana.
Incorporé paquetes. Antes solo estaba usando los que venían de
base en R, pero descubrí el mundo de los paquetes y creo
que sin duda hay que aprovecharlo. Principalmente añadí el uso del
paquete dplyr y ggplot2, el primero para
escribir código de forma más intuitiva (a mi juicio) y el segundo para
hacer gráficos más bonitos. No tienen nada que envidiarle a los paquetes
base, los cuales no dejé de lado.
No estoy usando pantallazos para las instalaciones, estoy usando GIFS. Creo que es mejor. No he podido crear el apartado de instalación de R, ya que me pidió que lo hiciera en windows pero yo tengo ubuntu. Me estoy consiguiendo un computador con windows para hacerlo :-) muy pronto. Lo tendré listo para la siguiente versión.
Intento seguir la misma estructura para cada sección: hago una
introducción de ellas y añado los conceptos principales a trabajar y
breves explicaciones para cada uno. Luego, el uso de ellos en
R mediante las funciones base y también usando
dplyr.
Creé la sección “Tablas de frecuencia”. Antes estaba unida a “Medidas descriptivas” y no profundizaba mucho en ellas. Aprendí a crear tablas de frecuencia mejores así que valía la pena ponerles su propia sección, con frecuencias acumuladas y todo.
Añadí los gráficos solicitados al apartado de “Medidas de correlación”, pero aún estoy aprendiendo a alinearlos bien. Se ven muy pequeños. Además, enchulé los histogramas de la sección “Medidas de dispersión” para que se entendiera mejor la idea.
Creé tablas resumen para cada base de datos, con ejemplos y todo. Las escondí con un botón de mostrar tabla/esconder tabla para que no ocupara tanto espacio. La tabla de las zarigueyas está lista pero estoy teniendo un pequeño problema con el botón.
Pendientes
Hacer el anexo.
Aparecen algunos errores al cargar ciertas librerias. Eso debo quitarlo. Listo para la siguiente reunión
Al parecer, la forma de abrir los enlaces es dando click derecho y luego abrir nueva pestaña. Parece que no funciona con click izquierdo directo.
La estadística descriptiva es una poderosa herramienta para comprender y resumir conjuntos de datos. Nos permite explorar la estructura, las tendencias y las características de los datos de manera sistemática y cuantitativa. En lugar de simplemente mirar números y cifras, la estadística descriptiva nos brinda un marco analítico para interpretar y extraer información significativa de los datos.
En este tutorial, exploraremos la estadística descriptiva utilizando RStudio. Para hacerlo, descargaremos bases de datos que contienen información sobre enfermedades cardíacas en humanos y zarigüeyas. A través de ejemplos prácticos, aprenderemos a aplicar técnicas estadísticas descriptivas utilizando el lenguaje de programación R y obtener conclusiones de estas.
Al utilizar estas bases de datos, por un lado, podremos analizar cómo se relacionan diferentes variables, como la edad, el sexo, los síntomas y los resultados de las pruebas médicas respecto a enfermedades cardiacas. Para el caso de las zarigüeyas, además de su edad y sexo, analizaremos las medidas de partes de su cuerpo, como el tamaño de sus patas, orejas, pecho y más. A su vez, exploraremos cómo estas técnicas descriptivas pueden ayudarnos a identificar patrones, tendencias y relaciones en los datos.
El siguiente enlace
nos llevará a la plataforma Kaggle, en donde está alojada base de datos
sobre enfermedades cardiacas. Una vez abierto, solo debemos pinchar en
“Download” y guardar el documento en donde se prefiera. Posteriormente,
ejecutaremos RStudio y procederemos a importar la base de
datos.
La extensión de la base de datos descargada es .csv, lo
cual significa que está escrita en un documento de texto, y cada está
dato separado por comas. RStudio nos hace bastante simple
el trabajo, solo debemos seleccionar las siguientes opciones:
\[
\textbf{File} \rightarrow \textbf{Import Dataset} \rightarrow
\textbf{From Text (base)} \rightarrow \textbf{Seleccionar base de datos}
\rightarrow \textbf{Import}
\]
Importación de la base de datos desde \(\textsf{RStudio}\)
Ya tenemos lista para usar nuestra base de datos sobre enfermedades cardiacas. Para la base de datos de zarigüeyas, debemos abrir el siguiente enlace y repetir los pasos anteriores.
La siguiente tabla es un resumen de nuestra base de datos sobre enfermedades cardiacas.
Mientras que la siguiente tabla es un resumen de la base de
datos sobre zarigüeyas
Las medidas descriptivas nos proporcionan información sobre diferentes aspectos de los datos, como su tendencia central, dispersión, posición y correlación. Entre las medidas descriptivas más comunes se incluyen la media, la mediana, la moda, el rango, la varianza, desviación estándar, el rango intercuartílico y la correlación de Pearson. Si no te suena alguna de las medidas mencionadas, no te preocupes porque en las siguientes subsecciones daremos más detalles de cada una.
Gracias a R y sus paquetes de base, podemos calcular
fácilmente medidas descriptivas utilizando funciones integradas. Estas
herramientas nos permitirán analizar y visualizar rápidamente la
distribución y las características de los datos.
Antes de comenzar a calcular estadísticas, calentemos los motores en
la consola de RStudio. Utilizando la función
head(), e introduciéndole como argumento el nombre de
nuestra base de datos de enfermedades cardiacas, heart,
podremos ver las primeras filas de datos.
También podemos chequear el número de observaciones que presenta
nuestra base de datos mediante la función length()
poniéndole como argumento cualquier variable.
## [1] 918
Podemos entender las medidas de tendencia central como estadísticas que representan la ubicación central o típica de un conjunto de datos. Las tres medidas de tendencia central más comunes son la media, la mediana y la moda.
Media: La media es el promedio aritmético de todos los valores en un conjunto de datos. Se calcula sumando todos los valores y dividiendo por el número total de valores.
Mediana: La mediana es el valor que divide al conjunto de datos en dos partes iguales, es decir, el valor medio cuando los datos están ordenados de manera ascendente o descendente.
Moda: La moda es el valor que ocurre con mayor frecuencia en un conjunto de datos.
Estas medidas son útiles para resumir y comprender la distribución de
los datos. En R, puedes calcular estas medidas fácilmente
utilizando funciones como mean() y median(),
para la media y la mediana respectivamente.
Podemos, por ejemplo, obtener la edad media de nuestra muestra:
## [1] 53.51089
Usando el paquete dplyr podemos obtener el mismo
resultado
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
heart %>% # Escogemos la base de datos y luego usamos el pipe %>%
pull(Edad) %>% # Obtenemos la variable Edad como vector
mean() # Calculamos el promedio de la edad## [1] 53.51089
O se puede ser más específicos en nuestro cálculo, y obtener la edad media de las personas que tienen alguna enfermedad cardiaca y las que no.
Primero calculemos la edad media de los que tienen enfermedad cardiaca usando las funciones base de R. Usando las herramientas lógicas, definiremos las variables de las personas que tienen una enfermedad cardiaca
tiene_enfermedad_cardiaca <- heart$EnfCard == 1 # Guardamos como variable todos los que tengan como observación de enfermedad cardiaca = 1
mean(heart[tiene_enfermedad_cardiaca, 1])## [1] 55.89961
Por otro lado, usando el paquete dplyr podemos calcular
el promedio de la edad los que no tienen enfermedad cardiaca.
heart %>%
filter(EnfCard == 0) %>% # Filtramos las filas que tengan la variable EnfCard = 0
pull(Edad) %>%
mean()## [1] 50.55122
Podemos decir entonces que en promedio, los pacientes de nuestra muestra que presentan alguna enfermedad cardiaca son cinco años mayor a las que no.
Otro ejercicio sería calcular la mediana de alguna variable que nos interese, por ejemplo, del colesterol.
## [1] 223
O usando dplyr
## [1] 223
Nos dio como resultado una mediana de 223 mm/dl para la variable del
colesterol. Ahora, notemos que podemos usar la función que sirve crear
histogramas,hist(), para crear una tabla de frecuencia
agrupada en intervalos. Para ello, dentro de los argumentos opcionales
que nos brinda la función, debemos desactivar plot con
plot = FALSE. Una vez creada nuestra tabla de frecuencia,
obtendremos intervalos de la forma [a,b) para nuestros datos. Para
efectos prácticos, le pediremos a R que solo nos lea las
primeras dos líneas del output de la función
hist que usaremos, finalizando con [1:2].
hist(heart$Col, plot = FALSE)[1:2] # Graficamos una tabla de frecuencia, y solo pedimos las primeras dos líneas del output del comando.## $breaks
## [1] 0 50 100 150 200 250 300 350 400 450 500 550 600 650
##
## $counts
## [1] 172 3 17 130 291 202 76 14 5 4 2 1 1
Tenemos un llamativo intervalo [0,50) con 172 datos. Significa que
hay 172 pacientes con niveles de colesterol sérico entre 0 y 50 mm/dl,
números demasiado bajos para niveles de colesterol sérico en seres
humanos. ¿Qué está ocurriendo? Hagamos una filtración de nuestra
variable colesterol, pidiéndole a R que nos muestre
específicamente los valores de cada paciente que tenga los niveles de
colesterol sérico por debajo de 50 mm/dl.
heart %>%
filter(Col < 50) %>%
# Filtramos los datos para tener una columna de valores de colesterol bajo a 50.
# Solicitamos a R los valores específicos de cada observación que haya -
# cumplido el filtro anterior.
pull(Col) ## [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [38] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [75] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [112] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
## [149] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Por las observaciones anteriores, podemos entender que nuestra base de datos nos está diciendo que a 172 pacientes no se les midió el colesterol total en su sangre al momento de examinarlos (o sus niveles de colesterol en la sangre realmente eran 0 mm/dl, pero omitiremos esta posibilidad ya que es imposible que ocurra). Por tanto, nuestros cálculos anteriores para obtener la mediana están incluyendo una cantidad considerable de valores iguales a 0, los cuales más nos vale ignorar o podríamos realizar un análisis sesgado.
Teniendo en cuenta lo anterior, presentamos los valores de la mediana solo considerando los valores de colesterol mayores que 0.
# Calculamos la mediana de la variable colesterol, aunque necesitamos-
# introducirle como argumento a la función median() un vector. -
# Para ello, filtramos de la variable colesterol el vector que contiene -
# los valores de colesterol mayores que 0.
median(heart$Col[heart$Col > 0]) ## [1] 237
O usando dplyr
heart %>%
filter(Col > 0) %>% # Primero filtramos los valores de colesterol mayores a 0.
pull(Col) %>% # De aquel filtro, solicitamos a R el vector con las observaciones
median() # Introducimos a la función median() el vector anterior.## [1] 237
La mediana varió 14 mg/dL respecto a la anterior con la muestra sesgada. ¿Cuánto variará el promedio, en un análisis no sesgado?
Calculando el promedio del colesterol sérico incluyendo las observaciones iguales a 0, es decir, en un cálculo sesgado, obtenemos
## [1] 198.7996
Hacemos lo mismo usando dplyr para los datos mayores que
0
## [1] 244.6354
Varió 46 mg/dL, lo que es un gran diferencia. Valió la pena ser cuidadosos.
Para calcular la moda no tenemos una función que venga de base en
\(\textsf{R}\), pero en internet
podemos encontrar un montón de soluciones a este problema. Para no
descargar un paquete, usaremos una función creada por un usuario del
foro stackoverflow. En este enlace
encontraremos la función creada y más opciones programadas por otros
usuarios.
Usémosla para comprobar cuál es el tipo de dolor de pecho más frecuente
## [1] ASY
## Levels: ASY ATA NAP TA
La observación que más se repite para la variable tipo de dolor de pecho es que la mayoría de los pacientes no presentan dolor de pecho. Podremos ver a detalle los valores de las otras observaciones en la sección Tablas de frecuencia.
Los cuartiles, deciles y percentiles son medidas estadísticas utilizadas para dividir un conjunto de datos ordenados en partes iguales o proporcionales. Estas medidas son importantes en la estadística descriptiva porque proporcionan información sobre la distribución de todos los datos.
Cuartiles: Los cuartiles dividen un conjunto de datos ordenados en cuatro partes iguales, es decir, en tres puntos que dividen los datos en cuatro grupos de igual tamaño. Los cuartiles más comúnmente utilizados son el primer cuartil (Q1), que representa el 25% de los datos, el segundo cuartil (Q2) que es igual a la mediana y divide los datos en dos partes iguales, y el tercer cuartil (Q3) que representa el 75% de los datos.
Deciles: Los deciles dividen un conjunto de datos en diez partes iguales, es decir, en nueve puntos que dividen los datos en diez grupos de igual tamaño. El primer decil (D1) representa el 10% de los datos, el segundo decil (D2) representa el 20% de los datos, y así sucesivamente.
Percentiles: Los percentiles dividen un conjunto de datos en cien partes iguales, es decir, en 99 puntos que dividen los datos en cien grupos de igual tamaño. El percentil P25 representa el 25% de los datos, el percentil P50 es igual a la mediana y representa el 50% de los datos, y el percentil P75 representa el 75% de los datos.
En R, podemos calcular cuartiles, deciles y percentiles
utilizando las funciones base quantile() y
summary()
Creemos un vector de datos de edad y con él calculemos cuartiles, deciles y percentiles.
datos_edad <- c(10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60)
# Calcular cuartiles
cuartiles <- quantile(datos_edad, probs = c(0.25, 0.5, 0.75))
# Con la opción props le pedimos que nos calcule el 25%, 50% y 75%
print(cuartiles)## 25% 50% 75%
## 22.5 35.0 47.5
# Calcular deciles
deciles <- quantile(datos_edad, probs = seq(0.1, 0.9, by = 0.1))
# Esta vez le pedimos que nos calcule desde el 10% al 90% de los datos, -
# cada uno separado por un 10%
print(deciles)## 10% 20% 30% 40% 50% 60% 70% 80% 90%
## 15 20 25 30 35 40 45 50 55
# Calcular percentiles
percentiles <- quantile(datos_edad, probs = seq(0.01, 0.99, by = 0.01))
print(percentiles)## 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 15% 16%
## 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 16.5 17.0 17.5 18.0
## 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 29% 30% 31% 32%
## 18.5 19.0 19.5 20.0 20.5 21.0 21.5 22.0 22.5 23.0 23.5 24.0 24.5 25.0 25.5 26.0
## 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 43% 44% 45% 46% 47% 48%
## 26.5 27.0 27.5 28.0 28.5 29.0 29.5 30.0 30.5 31.0 31.5 32.0 32.5 33.0 33.5 34.0
## 49% 50% 51% 52% 53% 54% 55% 56% 57% 58% 59% 60% 61% 62% 63% 64%
## 34.5 35.0 35.5 36.0 36.5 37.0 37.5 38.0 38.5 39.0 39.5 40.0 40.5 41.0 41.5 42.0
## 65% 66% 67% 68% 69% 70% 71% 72% 73% 74% 75% 76% 77% 78% 79% 80%
## 42.5 43.0 43.5 44.0 44.5 45.0 45.5 46.0 46.5 47.0 47.5 48.0 48.5 49.0 49.5 50.0
## 81% 82% 83% 84% 85% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96%
## 50.5 51.0 51.5 52.0 52.5 53.0 53.5 54.0 54.5 55.0 55.5 56.0 56.5 57.0 57.5 58.0
## 97% 98% 99%
## 58.5 59.0 59.5
También podemos obtener un resumen rápido usando
summary()
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 10.0 22.5 35.0 35.0 47.5 60.0
Podemos sacar algunas conclusiones con el resumen:
La edad mínima observada es de 10 años, y la máxima de 60 años.
La edad promedio entre los datos es de 35 años, que coincide con la mediana.
El 25% de las personas tiene 22.5 años o menos, la mitad tiene 35 años o menos, y el 75% tiene 47.5 años o menos.
En el análisis estadístico, las medidas de dispersión o variabilidad son fundamentales para comprender qué tanto varían o cuanto se diferencian respecto de su media. Mientras que las medidas de tendencia central, como la media, la mediana y la moda, proporcionan información sobre el valor típico o central de un conjunto de datos, las medidas de dispersión revelan la amplitud y la variabilidad de esos datos.
Rango: El rango es la diferencia entre el valor máximo y el valor mínimo en un conjunto de datos. Es la medida más simple de dispersión y proporciona una idea de la amplitud total de los datos, representando la máxima variabilidad presente en los datos.
Rango intercuartil (IQR): El rango intercuartil es la diferencia entre el tercer cuartil (Q3) y el primer cuartil (Q1). Representa la dispersión de los datos dentro del 50% central de la distribución y es una medida robusta que no se ve afectada por valores atípicos.
Varianza: La varianza es una medida de dispersión que describe cuánto varían los datos respecto a la media. Se calcula como la media de los cuadrados de las diferencias entre cada valor y la media del conjunto de datos.
Desviación estándar: La desviación estándar es la raíz cuadrada de la varianza y es una medida de dispersión más interpretable que la varianza. Indica cuánto se alejan, en promedio, los datos de la media y se expresa en las mismas unidades que los datos originales.
Para comenzar a aplicar los conceptos en R, comencemos
haciendo un cálculo sencillo. Veamos el rango de la edad de la muestra
de pacientes.
## [1] 49
El rango de la edad por tanto es 49 años. Parece un número grande, y
se podría pensar que la edad varía bastante en los pacientes de la
muestra. Sin embargo, y valiéndonos nuevamente del comando
hist(heart$Edad, plot=FALSE)[1:2] usado y explicado
anteriormente, podremos crear una tabla de frecuencias agrupadas en
intervalos
## $breaks
## [1] 25 30 35 40 45 50 55 60 65 70 75 80
##
## $counts
## [1] 5 27 61 103 120 196 185 139 58 20 4
Así, nos damos cuenta que para el grueso de las observaciones la edad varía poco, pues la gran mayoría de las edades se concentran entre los 45 y 65 años, un rango de 20 años. El rango por tanto sí cumplió con su función de representar la máxima variabilidad de los datos, pero tenemos que tener cuidado con su interpretación.
Por otro lado, el rango intercuartil por lo general sí nos entrega
una dispersión de datos más centralizada, a diferencia del rango.
Podemos llamarla en R con la función IQR(), y nos calculará
directamente qué tanto varían el 50% central de los datos.
## [1] 13
Según el rango intercuartil entonces, la dispersión de las edades dentro del 50% central de la distribución de datos es de 13 años.
Otra medida de variabilidad, usada por sus propiedades matemáticas y
utilidad en comparación a las anteriores es la varianza, o mejor
conocida por R por la función var(), la cual
nos permite chequear rápidamente propiedades básicas de esta medida de
dispersión. Observemos el siguiente comando, que involucra la variable
de la presión arterial en reposo y la constante numérica 2.
## [1] TRUE
El output de la función, TRUE, nos confirma que si
multiplicamos la constante numérica 2 por cada uno de los datos de la
variable presión arterial en reposo, y calculamos su varianza, es lo
mismo que multiplicar el cuadrado de la constante numérica 2 por la
varianza de cada uno de los datos. Hay muchas otras propiedades que se
pueden revisar fácilmente usando .
Un problema que le podríamos encontrar a la varianza es la poca
interpretación que podemos obtener de los calculos realizados con ella.
Por ejemplo, Dr. House difícilmente entenderá si le decimos que la
varianza de la presión arterial en reposo de sus pacientes es de 342
\((mmHg)^2\). Un forma de evitar estas
confusiones es usar la desviación estándar, que saca raíz cuadrada a la
varianza, y por tanto, las unidades de nuestros resultados serán iguales
a la unidades con la que se realizó la medida inicialmente. Basta con
llamar desde R la función sd()
Como la desviación estándar trabaja de modo directo con la media de
los datos, a modo de ejemplo, y para entender mejor su funcionamiento,
primero tendremos que calcular la media de alguna variable a interés.
Elegiremos la variable ritmo cardíaco máximo, aunque filtraremos los
datos para los pacientes que sí presentan angina al realizar ejercicio
usando funciones base de R
si_anginaejercicio_y_maxrc <- subset(heart, subset = EjeAng == "S", select = MaxRC)[[1]]
# Filtramos los pacientes que presentan angina con la función subset() y como argumentos -
# subset para filtramiento con herramientas lógicas, y select para escoger columnas, y -
# dentro de esta filtración solicitamos a R el vector numérico MaxRC con [1]
promedio_si_ang_ejercicio <- mean(si_anginaejercicio_y_maxrc)
# Calculamos el promedio de la variable creada con la función mean(), -
# que necesita un vector numérico como argumento.
promedio_si_ang_ejercicio # Imprimimos el resultado## [1] 125.3639
Y ahora calculemos el mismo promedio pero para los que no presentan
angina, usando el paquete dplyr
heart %>%
filter(EjeAng == "N") %>% # Filtramos las filas que no presentan angina al hacer ejercicio
pull(MaxRC) %>% # Le pedimos al dataframe que nos suelte la variable MaxRC como vector
mean() ## [1] 144.5722
Hay una diferencia considerable entre cada promedio. ¿Y qué nos dice la desviación estándar para cada caso? Veamos para el caso que sí presenta angina usando las funciones base
desv_estandar_si_angina <- sd(subset(heart, subset= EjeAng == "S", select = MaxRC)[[1]])
# Esta vez realizamos el cálculo de la desviación estándar directamente.
desv_estandar_si_angina # Imprimimos el resultado## [1] 20.45099
Y ahora para el caso que no presenta angina usando
dplyr, usando la misma lógica anterior.
## [1] 25.6102
Es posible concluir entonces que las personas que no presentan angina al ejercitarse tienen 5 latidos más por minuto en promedio que las que si presentan angina.
Con los cálculos anteriores de promedios y desviaciones estándar, procedemos a mostrar un par de histogramas para visualizar mejor los datos obtenidos.
La barra donde se encuentra el promedio de cada uno de los casos la representamos con el color rosa, mientras que los datos que están siendo abarcados por una desviación estandar (es decir, si \(\overline{x}\) representa la media de los datos y \(\sigma\) el valor de la desviación estándar, entonces dentro de las barras de colores están los datos entre los valores \(\overline{x} - \sigma\) y \(\overline{x} + \sigma\)) están representados con las barras moradas.
Una observación a hacer, y a modo de adelanto, podemos afirmar que entre las barras coloreadas de cada caso, se debiese concentrar aproximadamente el 68% de los datos. Podremos conocer más detalles estudiando la distribución normal en las siguientes secciones.
Las medidas de correlación son herramientas estadísticas utilizadas para cuantificar la relación entre dos variables. La correlación describe la dirección y la fuerza de la asociación entre las variables, lo que ayuda a comprender cómo cambian entre ellas.
Existen varias medidas de correlación, siendo la más común (y con la única que trabajaremos) la correlación de Pearson. Sin embargo, también se utilizan otras como la correlación de Spearman y la correlación de Kendall, especialmente cuando los datos no siguen una distribución normal o están en una escala ordinal.
Pendiente: mejorar visual de los gráficos
## [1] 1
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
En R, podemos calcular la correlación de Pearson utilizando la
función cor(). Con la base de datos sobre zarigüeyas
probaremos qué tanta correlación hay entre sus características
físicas.
En una conversación interna con las zarigüeyas, nos dieron una pista
de cuáles variables podrían llamarnos la atención para introducir como
argumento a la función cor().
# Usaremos el argumento use = "complete.obs" para que cor() haga los cálculos
# a pesar de existir observaciones NA en ambas variables.
cor(possum$earconch, possum$footlgth, use = "complete.obs")## [1] 0.7830499
El output anterior nos dice que hay una correlación positiva entre el tamaño de la oreja de la zarigüeya y el tamaño de su pata. Podemos interpretar el resultado como que en promedio mientras más grande la oreja de la zarigüeya, también su pata. En la siguiente sección veremos un gráfico de esta relación. Siguiendo esta idea, ¿qué tan fuerte podría ser la correlación entre la edad y el tamaño de las orejas?
## [1] 0.05340463
Una correlación casi nula. Quizás sea buena idea considerar el
crecimiento de la oreja hasta cierta edad, pues según Google, las
zarigüeyas crecen físicamente hasta aproximadamente los 2 años.
Intentemos obtener esta correlación usando dplyr
## [1] 0.2331032
La correlación aumentó, pero poco. Puede ser que no sean suficientes datos, o en verdad no hay una relación estrecha entre ambas variables.
Las tablas de frecuencia son herramientas fundamentales en estadística que nos permiten presentar la información resumida y ordenadamente por variable. Estas tablas muestran la frecuencia de ocurrencia de cada categoría o valor en una variable, así como las frecuencias acumuladas, porcentajes y otras medidas descriptivas importantes. Son especialmente útiles para analizar y comprender la distribución de datos categóricos y para realizar comparaciones entre diferentes grupos.
En R, podemos generar fácilmente tablas de frecuencia
utilizando la función base table(). Esta función cuenta la
frecuencia de ocurrencia de cada valor único en una variable y crea una
tabla de frecuencia. Además, podemos calcular frecuencias acumuladas,
porcentajes y otras medidas descriptivas utilizando funciones como
cumsum(), prop.table() y otras funciones de manipulación de datos en R,
que vienen incluidas en el paquete dplyr.
Creemos nuestra primera tabla de frecuencia usando
table() y la base de datos possum.
table(possum$sex, useNA = "always") #S eleccionamos la variable sexo y queremos que contabilice los "NA"##
## f m <NA>
## 43 61 0
Podemos usar más de una variable como muestra la siguiente tabla
##
## f m
## 1 3 7
## 2 7 9
## 3 11 16
## 4 6 8
## 5 6 7
## 6 7 5
## 7 1 6
## 8 0 1
## 9 2 0
O pedirle a nuestra tabla que nos muestre los datos en términos
porcentuales usando la función prop.table(), y luego
(usando un pipe), redondeamos los decimales a 4 mediante la función
round()
##
## f m
## 1 0.03 0.07
## 2 0.07 0.09
## 3 0.11 0.16
## 4 0.06 0.08
## 5 0.06 0.07
## 6 0.07 0.05
## 7 0.01 0.06
## 8 0.00 0.01
## 9 0.02 0.00
Como en la base de datos hay aproximadamente observaciones de 100 zarigüeyas, no era tan difícil predecir los porcentajes anteriores. En su mayoría, tenemos zarigüeyas de 3 años, principalmente machos.
Necesitaremos el paquete scales para lo siguiente.
Crear tablas más avanzadas usando dplyr puede parecer
más laborioso, pero es solamente listar los pasos mediante pipes.
Creemos una tabla (en estricto rigor, un dataframe) de frecuencia para
los pacientes de sexo masculino que presentan colesterol alto. La
siguiente puede parecer intimidante por su extensión, pero no es más que
una serie de funciones que ya hemos usado antes, y alguna extra.
heart %>%
filter(Sexo == "M", Col >= 200) %>% # Filtramos las filas mediante argumentos lógicos
count(TDP) %>% # Contamos los datos de la variable TDP y nos crea una nueva columna "n"
arrange(n) %>% # Ordenamos los valores del conteo anterior
mutate( # Creamos nuevas columnas
frec_absoluta_p = scales::percent(n/sum(n)), # Calculamos el porcentaje de los datos contados por count()
frec_acumulada_p = scales::percent(cumsum(n/sum(n))) # Usamos cumsum() para la frecuencia acumulada
) %>%
select( # Cambiamos el nombre a las variables para mayor estética
"Tipo dolor pecho" = TDP,
"Frecuencia absoluta" = n,
"Frecuencia absoluta porcentual" = frec_absoluta_p,
"Frecuencia acumulada porcentual" = frec_acumulada_p,
) Básicamente, filtramos a los pacientes de sexo masculino y que tenían un colesterol alto, y de ellos, contabilizamos qué tipo de dolor de pecho presenta cada uno. En base a ese conteo, calculamos las frecuencias relativas y acumuladas.
Una conclusión interesante de la tabla anterior es que entre los pacientes de sexo masculino que poseen el colesterol alto, un porcentaje no menor de ellos (40% aproximadamente), presenta algún tipo de dolor en el pecho atípico, o no presenta dolor en el pecho pero sí en otra zona del cuerpo.
Los gráficos nos permiten representar de forma efectiva la información de manera visual, facilitando la comprensión y la identificación de patrones, tendencias y relaciones en los datos. Hay una gran variedad de gráficos que podemos crear, presentamos algunos de ellos a continuación.
Gráficos de Barra : Representan datos cualitativos o comparaciones de cantidades mediante barras verticales u horizontales.
Histograma: Muestra la distribución de frecuencia de datos numéricos mediante barras contiguas.
Boxplot (Diagrama de caja y bigotes): Representa la distribución de un conjunto de datos numéricos mediante cuartiles, mediana y valores atípicos.
Gráfico Circular: Muestra la proporción de diferentes categorías como segmentos de un círculo.
Ojiva: Muestra la acumulación o frecuencia acumulativa de datos ordenados.
Gráfico de Dispersión: Representa la relación entre dos variables numéricas mediante puntos en un plano cartesiano.
En R, existen múltiples paquetes y funciones para crear gráficos que
se adaptan a diferentes tipos de datos y objetivos de visualización.
Para esta sección, usaremos exclusivamente el paquete
ggplot2, el cual ofrece una sintaxis amigable para crear
gráficos estéticamente agradables, personalizables y la capacidad de
trabajar con datos de forma más intuitiva que las funciones base de
R.
La razón de por qué el paquete ggplot2 se considera más intuitivo a
comparación de las funciones base de R, es porque
construimos los gráficos sobreponiendo en orden diferentes “capas”
creadas por funciones del paquete, y especificando cómo se deben mapear
los datos a elementos visuales.
Mostramos un resumen de cómo graficar con ggplot2:
Inicialización: Para comenzar a usar
ggplot2, primero debemos cargar el paquete con
library(ggplot2).
Sintaxis básica: La función
ggplot() se usa para iniciar la construcción de un gráfico.
La sintaxis básica es ggplot(datos = <datos>), donde
<datos> es el conjunto de datos que deseamos
visualizar.
Conector de capas: Si consideramos a la misma
función ggplot() como una capa, para continuar con la
siguiente capa debemos conectar con un + al final de
nuestra última función usada.
Capas geométricas: Luego del conector, debemos agregar capas geométricas para representar la forma de nuestros datos. Tenemos varias capas a elegir:
geom_bar() para un gráfico de barras.geom_histogram() para un gráfico de histograma.geom_boxplot() para un gráfico boxplot.geom_bar() con coord_polar() para un
gráfico circular.geom_line() para un gráfico ojiva.geom_point() para un gráfico de dispersion.Dentro de esta capa, se suele iniciar con la función
aes(), que solo en caso de ser necesario, contiene las
variables que se utilizarán para definir la estructura básica del
gráfico escogido. Además, se utiliza para mapear cada
variable seleccionada del conjunto de datos a
propiedades visuales de los elementos gráficos, como color, tamaño,
forma, posición, etc. Si las personalizaciones estéticas no están dentro
de esta función, significa que están siendo aplicadas a
todas las variables.
Hay muchas opciones para configurar para cada capa, las cuales pueden
ser encontradas en manuales específicos de ggplot2.
Presentamos un breve resumen con algunas de ellas.
fill: Define la variable asociada al color de las
barras.color: Establece el color del contorno de las
barras.width: Controla el ancho de las barras.ggplot(data = datos) +
geom_bar( aes(x = variable, y = conteo), fill = "categoría escogida", color = "black", width = 0.7)ggplot(data = datos) +
geom_histogram( fill = , color = "black", bins = 30) ggplot(data = datos) +geom_boxplot(fill = "lightpink", color = "darkred",
notch = TRUE)ggplot(data = datos) +geom_bar(aes(x = variable, y = valores),fill = "lightblue",color = "black", width = 0.8) +coord_polar(theta = "y")ggplot(data = datos) +
geom_line(aes(x = variable, y = frecuencia_acumulada),
color = "purple", size = 1.5)Ejes y etiquetas: Podemos agregar ejes
X e Y con xlab("Etiqueta eje X")
y ylab("Etiqueta eje Y"), respectivamente. Además, podemos
cambiar el título del gráfico con
ggtitle("Título del gráfico").
Facetas: Para dividir el gráfico en subgráficos
según una variable, podemos usar facetas con
facet_wrap(~variable) o
facet_grid(variable1 ~ variable2).
Escalas y temas: Podemos ajustar las escalas de
los ejes con scale_x_continuous() o
scale_y_continuous() y aplicar temas visuales con
theme() u otros temas predefinidos.
A cada función ggplot() al paquete ggplot2,
el argumento <data> debe ser un
dataframe. A causa de lo anterior, el paquete
dplyr será un buen complemento a ggplot2, pues
los outputs de sus funciones son precisamente dataframes.
Para comenzar a graficar, diseñaremos nuestro primer gráfico de
barras usando ggplot2 y la base de datos
heart. Tenemos que escoger una variable cualitativa que
queramos representar. Para ello, crearemos un dataframe, por medio del
paquete dplyr que nos contabilice qué tipo de
electrocardiograma en reposo muestran los pacientes, por lo que la
variable a utilizar será RepECG. Posteriormente,
introduciremos el dataframe creado a la función
ggplot(),
# Creamos el dataframe que contabiliza la variable RepECG
conteo_RepECG <- heart %>%
count(RepECG)
# Imprimimos el dataframe
conteo_RepECG# Creamos el gráfico de barras con ggplot2
ggplot(conteo_RepECG) +
geom_bar(aes(x = RepECG, y = n, fill = RepECG), stat = "identity") + # Agregamos la capa geométrica de gráfico de barras. Agregamos el argumento stat = "identity"
labs(x = "Tipo de electrocardiograma en reposo", y = "Número de observaciones", title = "Cantidad de observaciones para cada tipo de electrocardiograma en reposo") + # Añadimos etiquetas y título
theme(axis.text.x = element_text(angle = 45, hjust = 1)) # Rotar etiquetas del eje xNotemos que agregamos el argumento stat = "identity". la
razón de por qué no lo mencionamos antes, es que la función
geom_bar en ggplot2 no siempre debe llevar la
función stat. La función geom_bar por defecto
utiliza stat = "count", lo que significa que
automáticamente cuenta el número de ocurrencias de cada categoría en el
eje X y representa estas frecuencias como alturas de barras en el
gráfico. También podemos especificar explícitamente una función
stat diferente en geom_bar si necesitamos
realizar otro tipo de manipulación de los datos antes de la
representación visual. Por ejemplo, podemos usar
stat = "sum" para sumar los valores de una variable dentro
de cada categoría en el eje X y mostrar estas sumas como alturas de
barras en el gráfico. O como acabamos de hacer, podemos usar
stat = "identity" cuando ya tenemos los valores
precalculados de las alturas de las barras y no necesitamos que
ggplot2 realice ningún cálculo adicional.
Para el caso de la función theme(),
axis.text.x = element_text(angle = 45, hjust = 1) rota las
etiquetas del eje X (axis.text.x) en un ángulo de 45 grados
y las alinea horizontalmente hacia la derecha
(hjust = 1).
Ahora, volviendo al análisis del gráfico, es claro que el número de observaciones para el tipo de electrocardiograma en reposo “Normal” presentado por los pacientes es ampliamente superior a “LVH” y “ST”, los cuales son similares en su frecuencia.
Continuemos nuestro estudio de gráficos en ggplot2 con
un histograma. Para ello, necesitamos un conjunto de datos
cuantitativos, los cuales obtendremos de la variable colesterol de la
base de datos heart. Realizaremos una comparativa entre la
frecuencia para ciertos rangos de colesterol entre hombres y mujeres,
por lo que necesitamos modelar dos histogramas. Además, ya mencionamos
en la sección anterior que habían 172 observaciones para la variable
colesterol iguales a 0, así que tendremos que realizar un filtrado de
datos.
# Realizamos el filtrado, creando un dataframe llamado colesterol_pos
# que no contenga ningun valor de colesterol igual a 0.
colesterol_pos <- heart %>%
filter(Col > 0)
# Comenzamos introduciendo como argumento a nuestra función ggplot
# el dataframe creado.
ggplot(colesterol_pos) +
# Usamos las personalizaciones explicadas anteriormente.
geom_histogram(aes(x = Col), bins = 10, fill="pink", colour="black") +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
# Especificamos los puntos de quiebre en el eje x con la opción "breaks"
# Dentro de c va cada quiebre.
scale_x_continuous(breaks = c(0, 90, 140, 200, 260, 320, 370, 430, 490, 550, max(colesterol_pos$Col))) +
labs(
title = "Frecuencia de niveles de colesterol entre hombres y mujeres ",
x = "Niveles de colesterol [mg/dL]",
y = "Frecuencia"
) +
# Dividimos el histograma en dos, en base a la variable Sexo.
facet_grid(Sexo ~.)Claramente hay un intervalo donde que agrupa la mayor frecuencia para
las observaciones. La gran mayoría de los pacientes, tanto sexo
masculino como femenino, tenían entre 220 a
260 mg/dL de colesterol sérico cuando se les
tomó la muestra. La comparación entre las frecuencias tanto para sexo
masculino y femenino parece seguir una misma tendencia, pese a que
tengamos un número menor de observaciones para las pacientes de sexo
femenino.
Según valores de la literatura médica, los niveles óptimos de colesterol
sérico son por debajo de 200 mg/dL, por lo que sería una
buena idea aumentar la cantidad de barras, y así tener una mayor
claridad, al tener un histograma más detallado, de los valores que se
presentan en los intervalos cercanos a niveles no recomendados. Bastaría
con cambiar el número de bins.
Proseguimos el estudio de gráficos con un boxplot, esta vez usando la
base de datos possum. Esta base de datos posee bastantes
variables numéricas que podemos escoger como nuestro conjunto de datos
para graficar. Observaremos visualmente, un hecho que difícilmente
podríamos haber asimilado si hubiésemos tenido todos los datos dispersos
frente a nuestros ojos. Grafiquemos un boxplot entre el tamaño del pie
de las zarigüeya y su ubicación.
ggplot(possum, aes(x = Pop, y = footlgth)) +
# Color de llenado como fill, color de bordes como color,
# alpha indica la transparencia de las cajas y bigote, va de 0 a 1,
# width controla el ancho de las cajas y el bigote.
geom_boxplot(fill = "lightblue", color = "darkblue", alpha = 0.7, width = 0.5, notch = FALSE) +
# theme_minimal: diseño de gráfico minimalista
theme_minimal() +
# Ajustamos las etiquetas y el título.
labs(
title = "Distribución de longitud de pies de zarigüeya por locación",
x = "Locación",
y = "Longitud del pie [cm]"
)Hagamos una interpretación de los boxplot:
explicar la longitud de los bigotes y su concentración, en particular, q el bigote inferior es más corto de ambos entonces entre el 25% de los pies más pequeños se concentran más que el 25% de los pies más grandes
explicar que en el boxplot derecho la mediana está más tirada hacia Q3, eso quiere decir que los tamaños de los pies entre el 25% y 50% de las zarigueyas está más disperso
mostrar rango intercuartilico
Se puede apreciar claramente que las zarigüeyas de Victoria tienen un pie más grande que las zarigüeyas de New South Wales or Queensland, y por una gran diferencia. Ciertamente hay casos extremos, que son los puntos aislados en ambos boxplot,
Gráfico de dispersión de datos para la correlación entre el tamaño de la pata y oreja de las zarigueyas.
ggplot(data = possum, aes(x = footlgth, y = earconch)) + geom_point(alpha = 0.4, color = "blue", aes(shape = sex))## Warning: Removed 1 rows containing missing values (`geom_point()`).
Recopilación de problemas resueltos del libro Introducción a la probabilidad de Luis Rincón.
Comenzaremos con ejercicios de análisis combinatorio. Cargamos el
paquete gtools que usaremos bastante.
1.- (P.76, Corredores) ¿De cuántas maneras diferentes pueden clasificarse los tres primeros lugares de una carrera de n corredores?
Sí nos importa el orden de las personas, pero no vamos a reponer a ninguna, puesto que no queremos que la misma persona obtenga el primer y segundo lugar a la vez. Para el primer lugar pueden clasificarse \(n\), para el segundo \(n-1\) y para el tercero \(n-2\). Así, pueden clasificarse de \(n(n-1)(n-2)\) maneras.
La siguiente función nos creará una matriz con las posibles permutaciones para los 3 lugares, donde el argumento es los n corredores.
tres_lugares <- function(x) {
resultado <- permutations(x, 3, 1:x)
permutaciones <- x*(x-1)*(x-2)
print(resultado)
print(paste("El número de permutaciones es", permutaciones))
}Veamos por ejemplo para n = 3
## [,1] [,2] [,3]
## [1,] 1 2 3
## [2,] 1 3 2
## [3,] 2 1 3
## [4,] 2 3 1
## [5,] 3 1 2
## [6,] 3 2 1
## [1] "El número de permutaciones es 6"
2.- (P.77, Mesa circular) ¿De cuántas maneras diferentes pueden sentarse n personas en una mesa circular?
Si etiquetamos a cada persona con un número y consideramos que cada
posible configuración tiene en cuenta cuál persona etiquetada está
frente a cuál, y además cada asiento está separado a la misma distancia
entre sí, tenemos n! maneras distintas. Por ejemplo, una
configuración podría ser {1, 2, 3}, que sería distinta a
{1, 3, 2}, porque en la primera configuración, 1 está
frente a 3, mientras que en la segunda, 1 está frente a 2.
Una segunda forma de ver el problema sería nuevamente etiquetar a las
personas con un número, pero solo consideramos quién está a la derecha
de quién, por lo que tenemos n!/n maneras diferentes, ya
que tenemos configuraciones que se repiten, por ejemplo,
{1, 2, 3} es igual a {3, 1, 2}.
Un comando de R que nos muestre las posibles
configuraciones para la segunda forma de ver el problema podría ser
permutations(n, 3, 1:n)[1:(factorial(n)/n), ], para
n a elección.
3.- (P.79, Rumores) Tengo dudas con este
ejercicio En un pueblo de n + 1 habitantes, uno de
ellos le rumorea algo a una segunda persona, ésta, a su vez, se lo
cuenta a una tercera persona (que puede ser la primera persona), y así
sucesivamente. Determine la probabilidad de que el rumor se transmita
r veces sin que regrese a la primera persona.
Experimento: n + 1 personas se
traspasan, una tras otra, un rumor r veces.
|Espacio muestral| = \(n^r\) = \(\Omega\)
Evento: El rumor no vuelve a la primera persona =
E
Podemos restarle a los casos totales, el caso en el que el rumor sí vuelve a la primera persona después de r transmiciones. Hay \(n^{r-1}(n-1)\) formas de que este caso ocurra. Así,
\[\begin{equation*} \mathbb{P}(E) = \frac{n^r-n^{r-1}(n-1)}{n^r} \end{equation*}\]library(ggplot2)
# Definir la función de probabilidad
probabilidad_rumor <- function(n, r) {
return ((n^(r-1) * (n-1)) / (n^r))
}
# Crear un data frame con diferentes valores de n y r
n_valores <- seq(1, 10, 2) # Valores de n de 1 a 10
r_valores <- seq(1, 10, 2) # Valores de r de 1 a 5
df <- expand.grid(n = n_valores, r = r_valores)
df$probabilidad <- probabilidad_rumor(df$n, df$r)
# Crear el gráfico de puntos con ggplot2
ggplot(df, aes(x = n, y = r, color = probabilidad)) +
geom_point(size = 3) +
scale_color_gradient(low = "lightblue", high = "darkblue") +
labs(x = "Valor de n", y = "Valor de r", title = "Probabilidad de que el rumor no vuelva a la primera persona") +
theme_minimal()4.- (P.92, Las cajas de cerillos de Banach). Una persona tiene dos cajas de cerillos, cada una de las cuales contiene n cerillos. La persona coloca una caja en cada uno de sus bolsillos izquierdo y derecho, y cada vez que requiere un cerillo elige uno de sus bolsillos al azar y toma de la caja correspondiente uno de los cerillos. ¿Cuál es la probabilidad de que en el momento en el que la persona se da cuenta de que la caja del bolsillo izquierdo está vacía, en la caja del bolsillo derecho haya exactamente r cerillos?
Experimento:
Espacio muestral:
Evento:
EStá difícil este. Me ha costado harto.
RCargar el paquete dplyr. Seguir
explicando
Uso básico del pipe (%>%): El pipe se utiliza para encadenar operaciones de manera secuencial, pasando el resultado de una operación como entrada a la siguiente operación. La sintaxis básica del pipe es la siguiente:
En esta sintaxis:
objeto_inicial es el objeto inicial que deseamos
transformar o manipular.operacion1(), operacion2(), …,
operacionN() son las operaciones que deseamos aplicar al
objeto inicial en secuencia.Ejemplo de uso:
# Creamos un vector de números
numeros <- c(1, 2, 3, 4, 5)
# Utilizamos el pipe para aplicar operaciones secuenciales
resultado <- numeros %>%
sum() %>% # Calculamos la suma de los números
sqrt() %>% # Calculamos la raíz cuadrada del resultado
round(digits = 2) # Redondeamos el resultado a 2 decimales
print(resultado) # Imprimir el resultado## [1] 3.87
Enseñar a instalar paquetes con gif