# Leemos y guardamos la base de datos en el objeto big5
<- read.csv("https://david-ti.github.io/introstats/data/big_five.csv") big5
Apuntes de R
Parte 2: Estadística descriptiva
Introducción a gráficos en R
Ahora que conocemos los elementos básicos para operar en R vamos a empezar a aplicar lo aprendido a un ejemplo real. Para este ejemplo vamos a utilizar una base de datos de respuestas al cuestionario de los “Big 5”, basado en una influyente teoría de personalidad desarrollada originalmente por McCrae y Costa (1987).
El comando read.csv
requiere un argumento principal, la dirección donde se encuentra el archivo. Esta dirección puede ser un lugar en el disco duro de la computadora local o una dirección web, como en el ejemplo a continuación:
Histogramas
Partamos por ver la distribución de los datos de la variable age
(edad) en la base de datos big5
. Un gráfico óptimo para examinar la distribución de una variable es un histograma, que podemos producir con la función hist
. Es importante recordar que un histograma nos permite visualizar como están distribuidos los datos en un variable cuantitativa continua. De este modo, el grafico se construye a partir de la agrupación de datos, donde el eje horizontal del gráfico va a estar dividio en grupos y el eje vertical nos va a indicar la frecuencia de datos concentrados en cada grupo.
# Usa por defecto el método de Sturges
hist(big5$age)
Podemos también crear una versión con un número distinto de grupos usando el argumento breaks
que controla este aspecto del histograma:
# Acá estamos pidiendo que R haga siete grupos
# Cuando se usa esta opción R lo considera como una "sugerencia"
hist(big5$age, breaks = 7)
# Acá estamos pidiendo usar el método de Freedman y Diaconis
hist(big5$age, breaks = "FD")
O podemos elaborar más nuestro gráfico usando argumentos adicionales:
hist(big5$age
breaks = "FD" # Como decidir cuantos grupos usar
, main = "Mi histograma" # Título
, axes = FALSE # No dibujar los ejes
, xlab = "Edad" # Etiqueta eje x
, ylab = "Frequencia" # Etiqueta eje y
, col = "dodgerblue4") # Color a usar en el gráfico
,
axis(1) # Dibujar el eje x
axis(2, las = 1) # Dibujar el eje y con etiquetas horizontales
Podemos también hacer un histograma de los promedios de cada persona en las preguntas de extroversión.
<- rowMeans(big5[,c("e1","e2","e3","e4","e5","e6","e7","e8","e9","e10")])
promedios_extro
hist(promedios_extro
breaks = "FD" # Como decidir cuantos grupos usar
, main = "Promedios de extroversión" # Título
, axes = FALSE # No dibujar los ejes
, xlab = "Promedios extroversión" # Etiqueta eje x
, ylab = "Frequencia" # Etiqueta eje y
, col = "#4393C3") # Color a usar en el gráfico
,
axis(1) # Dibujar el eje x
axis(2, las = 1) # Dibujar el eje y con etiquetas horizontales
Diagramas de dispersión
Ahora que hemos visto las distribuciones de dos variables, age
y promedios_extro
podemos usar un diagrama de dispersión para examinarlas en conjunto usando el comando plot
que recibe como primer argumento los datos que irán en el eje x, y como segundo argumento los datos que se representarán en el eje y. Recordar que un diagrama de dispersión nos permite visualizar como se relacionan los datos de dos variables cuantitativas, permitiendo ver que tan relacionadas se encuentran.
plot(big5$age, promedios_extro)
Y podemos personalizar también este gráfico:
plot(big5$age, promedios_extro
main = "Diagrama de edad y extroversión" # Título
, axes = FALSE # No dibujar los ejes
, xlab = "Edad" # Etiqueta eje x
, ylab = "Promedio de extroversión" # Etiqueta eje y
, xlim = c(0,80) # Rango del eje x
, ylim = c(0,5) # Rango del eje y
, pch = 18 # Elegir símbolo
, col = "#4393C3") # Color
,
axis(1) # Dibujar el eje x
axis(2, las = 1) # Dibujar el eje y con etiquetas horizontales
En este último ejemplo cambiamos el tipo de símbolos con el argumento pch
. Las opciones que pueden ser usadas en R son las siguientes:
Gráficos de barra
Para ver ejemplos de gráficos de barra vamos a trabajar con una nueva base de datos que pueden descargar desde aquí. Esta base de datos tiene datos sobre los pasajeros del Titanic, y vamos a explorar los datos disponibles.
# Leemos y guardamos la base de datos en el objeto titanic
<- read.csv("https://david-ti.github.io/introstats/data/titanic.csv") titanic
Examinemos los datos en esta base de datos:
str(titanic)
'data.frame': 891 obs. of 12 variables:
$ PassengerId: int 1 2 3 4 5 6 7 8 9 10 ...
$ Survived : int 0 1 1 1 0 0 0 0 1 1 ...
$ Pclass : int 3 1 3 1 3 3 1 3 3 2 ...
$ Name : chr "Braund, Mr. Owen Harris" "Cumings, Mrs. John Bradley (Florence Briggs Thayer)" "Heikkinen, Miss. Laina" "Futrelle, Mrs. Jacques Heath (Lily May Peel)" ...
$ Sex : chr "male" "female" "female" "female" ...
$ Age : num 22 38 26 35 35 NA 54 2 27 14 ...
$ SibSp : int 1 1 0 1 0 0 0 3 0 1 ...
$ Parch : int 0 0 0 0 0 0 0 1 2 0 ...
$ Ticket : chr "A/5 21171" "PC 17599" "STON/O2. 3101282" "113803" ...
$ Fare : num 7.25 71.28 7.92 53.1 8.05 ...
$ Cabin : chr "" "C85" "" "C123" ...
$ Embarked : chr "S" "C" "S" "S" ...
head(titanic)
PassengerId Survived Pclass
1 1 0 3
2 2 1 1
3 3 1 3
4 4 1 1
5 5 0 3
6 6 0 3
Name Sex Age SibSp Parch
1 Braund, Mr. Owen Harris male 22 1 0
2 Cumings, Mrs. John Bradley (Florence Briggs Thayer) female 38 1 0
3 Heikkinen, Miss. Laina female 26 0 0
4 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35 1 0
5 Allen, Mr. William Henry male 35 0 0
6 Moran, Mr. James male NA 0 0
Ticket Fare Cabin Embarked
1 A/5 21171 7.2500 S
2 PC 17599 71.2833 C85 C
3 STON/O2. 3101282 7.9250 S
4 113803 53.1000 C123 S
5 373450 8.0500 S
6 330877 8.4583 Q
Esta base de datos tiene 891 filas y 12 variables. Entre las variables que incluye están:
Survived
: indica con un 1 si la persona sobrevivió o 0 si murióPclass
: indica la clase en la que el pasajero viajaSex
: indica el sexo registrado de cada pasajera y pasajeroAge
: edad
Partamos por ver cuántas personas sobrevivieron:
table(titanic$Survived)
0 1
549 342
barplot(table(titanic$Survived)
names.arg = c("Murieron","Sobrevivieron")
, )
Recordar que a diferencia de un histograma, un gráfico de barras permite visualizar la distribución de la variable categórica. Esto implica que el eje horizontal del gráfico de barras representa categorías y no rangos de una cantidad.
Podemos ver la proporción de cuantas personas sobrevivieron:
prop.table(table(titanic$Survived))
0 1
0.6161616 0.3838384
barplot(prop.table(table(titanic$Survived))
names.arg = c("Murieron","Sobrevivieron")
, )
Podemos ver que la proporción de sobrevivientes es aproximadamente 0.38, lo que quiere decir que aproximadamente 38% de los pasajeros del Titanic sobrevivió.
Una pregunta interesante de hacerse, es si esta proporción es igual para todas las clases de pasajeros; es decir, si se mantiene esta proporción de sobrevivientes en las clases 1, 2 y 3. ¿Por qué es interesante esta pregunta? Porque si la proporción de sobrevivientes es muy diferente en las distintas clases (posteriormente debemos generar análisis para ver si estas diferencias son efectivamente estadísticamente significativas) se podría hipotetizar porqué esto ocurrió.
Para calcular la proporción de sobrevientes según clase, primero haremos una tabla de frecuencia de supervivencia según clase, y luego una tabla de proporción. En esta tabla se podrá ver la proporción de sobrevientes del total según cada clase, es decir, la proporción de sobrevivientes para la clase 1, la clase 2 y la clase 3. (Como complemento, podemos observar la proporción de personas que murieron del total según cada clase).
# Tabla de frecuencia
table(titanic$Pclass,titanic$Survived)
0 1
1 80 136
2 97 87
3 372 119
# Tabla de proporciones dentro de cada clase
prop.table(table(titanic$Pclass,titanic$Survived)
margin = 1) ,
0 1
1 0.3703704 0.6296296
2 0.5271739 0.4728261
3 0.7576375 0.2423625
barplot(prop.table(table(titanic$Pclass,titanic$Survived), margin = 1)
beside = TRUE
, legend = TRUE
, names.arg = c("Murieron","Sobrevivieron")
, )
Para crear la tabla de proporciones y el gráfico de barras de esta, agregamos el argumento margin = 1
, que quiere decir que el análisis de proporción se hará respecto al total de la fila. En este caso, las filas representan cada clase, por lo tanto la tabla mostrará la proporción de personas que sobrevivieron (y que murieron) en cada clase sobre el total de esa misma clase.
Podemos ver que si sumamos los valores por fila (hacia el lado) el resultado de esta sumatoria es 1. Y en el gráfico de barras, la suma de las barras de cada clase (representadas por los diferentes colores) es 1.
Este análisis de proporción también lo podemos hacer considerando como total el grupo de sobrevivientes y el grupo de personas que murieron. Así, nos podemos preguntar ¿De las personas que sobrevivieron, qué proporción era de primera clase? Para generar esta tabla usaremos el argumento margin = 2
, que indica que queremos que considere como total la suma de los valores de cada columna. En este caso, columna 0 representa personas que murieron y columna 1 personas que sobrevivieron.
# Tabla de frecuencia
table(titanic$Pclass,titanic$Survived)
0 1
1 80 136
2 97 87
3 372 119
# Tabla de proporciones dentro de cada clase
prop.table(table(titanic$Pclass,titanic$Survived)
margin = 2) ,
0 1
1 0.1457195 0.3976608
2 0.1766849 0.2543860
3 0.6775956 0.3479532
barplot(prop.table(table(titanic$Pclass,titanic$Survived), margin = 2)
beside = TRUE
, legend = TRUE
, names.arg = c("Murieron","Sobrevivieron")
, )
Podemos ver que si sumamos los valores por columna (hacia abajo) el resultado de esta sumatoria es 1. Y en el gráfico de barras, la suma de todas las barras por grupo (murieron, sobrevivieron) es 1.
Tablas
Ya hemos visto como el comando table
puede ser utilizado para generar tablas de frequencia o de proporciones de una o dos variables. La función addmargins
agrega la suma de los datos correspondientes a las distintas categorías de la tabla construida.
# Tabla de frecuencias
addmargins(table(titanic$Pclass,titanic$Survived))
0 1 Sum
1 80 136 216
2 97 87 184
3 372 119 491
Sum 549 342 891
# Tabla de proporciones dentro de cada clase
addmargins(prop.table(table(titanic$Pclass,titanic$Survived)
margin = 1)) ,
0 1 Sum
1 0.3703704 0.6296296 1.0000000
2 0.5271739 0.4728261 1.0000000
3 0.7576375 0.2423625 1.0000000
Sum 1.6551818 1.3448182 3.0000000
# Tabla de proporciones entre sobrevivientes o fallecidos (columnas)
addmargins(prop.table(table(titanic$Pclass,titanic$Survived)
margin = 2)) ,
0 1 Sum
1 0.1457195 0.3976608 0.5433803
2 0.1766849 0.2543860 0.4310708
3 0.6775956 0.3479532 1.0255488
Sum 1.0000000 1.0000000 2.0000000
Generando tablas de resumen con aggregate
Pero también podemos generar tablas de resumen que nos muestren resultados descriptivos para subgrupos. Una función que nos permite generar este tipo de tablas es la función agregate
.
Esta función requiere de al menos tres argumentos:
- Los datos que queremos resumir
- Las categorías en las que queremos dividir los datos
- La función que queremos aplicar a cada subgrupo
Generemos por ejemplo una tabla que nos muestre cuál es el promedio de edad de las personas que sobrevivieron y de las que fallecieron.
# titanic$Age es el dato que queremos resumir
# titanic$Survived es el dato en que queremos agrupar
# FUN es una abreviación de función, indicando lo que queremos hacer
aggregate( titanic$Age
by = list(titanic$Survived)
, FUN = mean) ,
Group.1 x
1 0 NA
2 1 NA
Pero algo salió mal… podemos ver que en vez de mostrar resultados, R nos muestra solo NA
que en R indica que el valor no está disponible. Esto suele ocurrir cuando entre nuestros datos hay valores perdidos. Una manera de ver si este es el caso es usar la función is.na
(que nos permite evaluar si un dato es NA
) en combinación con la función table
.
# Evalúa cada observación en Age para ver si es NA
# Es lento revisar cada observación
is.na(titanic$Age)
[1] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
[13] FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE
[25] FALSE FALSE TRUE FALSE TRUE TRUE FALSE TRUE TRUE FALSE FALSE FALSE
[37] TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE TRUE
[49] TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[61] FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE
[73] FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE
[85] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
[97] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE
[109] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[121] FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE
[133] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[145] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[157] FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[169] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[181] TRUE TRUE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE
[193] FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE
[205] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[217] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[229] FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[241] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[253] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[265] TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE
[277] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[289] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE
[301] TRUE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE
[313] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[325] TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
[337] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
[349] FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE TRUE TRUE
[361] FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE TRUE FALSE FALSE FALSE
[373] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[385] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[397] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[409] FALSE TRUE TRUE TRUE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE
[421] TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE
[433] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[445] TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE
[457] FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE
[469] TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[481] FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE
[493] FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE
[505] FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[517] FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE
[529] FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE
[541] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[553] TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE
[565] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
[577] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[589] FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE
[601] FALSE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
[613] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[625] FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE
[637] FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[649] TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE
[661] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE FALSE
[673] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[685] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
[697] FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[709] FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[721] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE
[733] TRUE FALSE FALSE FALSE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE
[745] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[757] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[769] TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE
[781] FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE
[793] TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[805] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE
[817] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE
[829] TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE TRUE
[841] FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE
[853] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE
[865] FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[877] FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[889] TRUE FALSE FALSE
# Esto resume los resultados diciendo cuántos datos NA hay
table(is.na(titanic$Age))
FALSE TRUE
714 177
Dado que tenemos datos perdidos (177 en este caso), tenemos que agregar un argumento adicional a nuestra función llamado na.rm
, que corresponde a una abreviación de “remover NAs”, la cual le indicará a la función que debe ignorar estos datos.
aggregate( titanic$Age
by = list(titanic$Survived)
, FUN = mean
, na.rm = TRUE) ,
Group.1 x
1 0 30.62618
2 1 28.34369
Al agregar esta instrucción adicional podemos ver ahora los resultados. Una de las ventajas de usar aggregate
es que podemos usarla para generar cualquier tipo de resultados cambiando la función indicada en el argumento FUN
:
# Veamos la edad de la persona menor en cada categoría
aggregate( titanic$Age
by = list(titanic$Survived)
, FUN = min
, na.rm = TRUE) ,
Group.1 x
1 0 1.00
2 1 0.42
# Veamos la edad de la persona mayor en cada categoría
aggregate( titanic$Age
by = list(titanic$Survived)
, FUN = max
, na.rm = TRUE) ,
Group.1 x
1 0 74
2 1 80
Describiendo la distribución de variables
Existen indicadores que nos permiten caracterizar propiedades de las distribuciones de datos, siendo los más importantes la tendencia central y la dispersión.
Medidas de tendencia central
Media o promedio (y datos perdidos)
En clase discutimos tres medidas de tendencia central. La primera, el promedio, la hemos usado ya en múltiples oportunidades.
Si quiero promediar notas de 10 controles, puedo usar el comando mean
entregando como argumentos el vector de notas:
<- c(4.8,5.3,6.2,4.6,5.9,6.0,5.3,5.1,6.5,4.2)
notas_de_controles
mean(notas_de_controles)
[1] 5.39
El cálculo de la media es sencillo, pero en casos donde nuestros datos tienen datos perdidos, codificados con NA
por R, el comando no funcionará directamente:
# Incluyamos un dato perdido
<- c(4.8,5.3,6.2,NA,5.9,6.0,5.3,5.1,6.5,4.2)
notas_de_controles_con_NA
mean(notas_de_controles_con_NA)
[1] NA
Podemos ver que R nos arroja ahora un resultado NA
. En general, cada vez que R encuentra un NA
en los datos el programa considerará que no puede ejecutar el cálculo que se requiere (debido a que no tiene información respecto a ese dato).
Sin embargo, podemos indicar con un argumento adicional que R debe ignorar datos perdidos, realizando el cálculo solo considerando los datos disponibles. El argumento a utilizar en este caso es na.rm
(NA remove o remover NAs), el cual debemos activar especificando el valor TRUE
.
# Incluyamos un dato perdido
<- c(4.8,5.3,6.2,NA,5.9,6.0,5.3,5.1,6.5,4.2)
notas_de_controles_con_NA
mean(notas_de_controles_con_NA, na.rm = TRUE)
[1] 5.477778
Podemos ver que ahora R ha calculado el promedio de las notas ignorando el dato perdido.
Finalmente, podemos gráficar la media en un histograma usando el comando abline
(línea A B… como en las funciones lineales), especificando que queremos una línea vertical (argumento v
) ubicada en la media, de color rojo (col
), y vamos a querer una línea más gruesa (lwd
: de line width
, literalmente grosor de la línea).
# Dibujar el histograma
hist(notas_de_controles)
# Agregar una linea roja en el promedio
abline(v = mean(notas_de_controles)
col = 'red'
, lwd = '3') ,
Mediana
La mediana puede ser calculada con el comando median
de forma similar a como obtuvimos la media.
median(notas_de_controles)
[1] 5.3
median(notas_de_controles_con_NA, na.rm = TRUE)
[1] 5.3
# Se calcula promediando observaciones intermedias
<- c(1,2,3,4,5,6)
numero_par_de_datos median(numero_par_de_datos)
[1] 3.5
# Se calcula identificando el valor medio
<- c(1,2,3,4,5)
numero_impar_de_datos median(numero_impar_de_datos)
[1] 3
Al igual que con la media, podemos también agregar una línea vertical para la mediana en el mismo histograma que creamos al trabajar con la media.
# Dibujar el histograma
hist(notas_de_controles)
# Agregar una linea roja en el promedio
abline(v = mean(notas_de_controles)
col = 'red'
, lwd = '3')
,
# Agregar una linea verde en la mediana
abline(v = median(notas_de_controles)
col = 'green'
, lwd = '3') ,
Moda
Para ver un ejemplo de cálculo de la moda vamos a utilizar la base de datos sobre el Titanic. Examinemos la variable Sex
de los pasajeros para determinar la moda entre las edades. Para esto podemos hacer una tabla:
table(titanic$Sex)
female male
314 577
Podemos ver que en el caso de esta variable, la moda es “male”.
Medidas de dispersión
Revisemos las medidas de dispersión que discutimos en clases.
Rango
El rango puede ser calculado fácilmente con las funciones max
(dato máximo) y min
(dato mínimo). Podemos también pedir ambos datos directamente usando el comando range
.
max(notas_de_controles)
[1] 6.5
min(notas_de_controles)
[1] 4.2
# recordemos que el rango es dato máximo menos mínimo
max(notas_de_controles) - min(notas_de_controles)
[1] 2.3
range(notas_de_controles)
[1] 4.2 6.5
range(notas_de_controles_con_NA, na.rm = TRUE)
[1] 4.2 6.5
Rango interquartil
El rango interquartil puede ser calculado directamente con la función IQR
(Inter Quartile Range).
IQR(notas_de_controles)
[1] 1.1
Desviación estándar y varianza
La desviación estándar y la varianza pueden ser calculadas respectivamente con los comandos sd
(del inglés standard deviation) y var
(varianza).
sd(notas_de_controles)
[1] 0.7460265
var(notas_de_controles)
[1] 0.5565556
sd(notas_de_controles_con_NA, na.rm = TRUE)
[1] 0.7344688
var(notas_de_controles_con_NA, na.rm = TRUE)
[1] 0.5394444
Cuantiles y boxplots
R nos permite calcular cualquier medida de posición usando el comando quantile
. Por ejemplo, si queremos ver los valores de los deciles podemos indicarlos en el argumento probs
. Veamos los deciles (dividimos la distribución en 10 partes iguales) de la variable Age
en la base sobre el Titanic.
Cuantiles
quantile(titanic$Age
probs = c(.1,.2,.3,.4,.5,.6,.7,.8,.9), na.rm = TRUE) ,
10% 20% 30% 40% 50% 60% 70% 80% 90%
14.0 19.0 22.0 25.0 28.0 31.8 36.0 41.0 50.0
Si queremos ver los quintiles (dividimos la distribución en 5 partes iguales):
quantile(titanic$Age
probs = c(.2,.4,.6,.8), na.rm = TRUE) ,
20% 40% 60% 80%
19.0 25.0 31.8 41.0
Si queremos ver los cuartiles (dividimos la distribución en 4 partes iguales):
quantile(titanic$Age
probs = c(.25,.5,.75), na.rm = TRUE) ,
25% 50% 75%
20.125 28.000 38.000
Podemos comparar los resultados que obtenemos usando el comando IQR
con el comando quantile
:
IQR(titanic$Age, na.rm = TRUE)
[1] 17.875
<- quantile(titanic$Age
tercer_cuartil probs = c(.75), na.rm = TRUE)
,
<- quantile(titanic$Age
primer_cuartil probs = c(.25), na.rm = TRUE)
,
- primer_cuartil tercer_cuartil
75%
17.875
Boxplots
Una representación gráfica muy útil para visualizar una distribución es conocida como diagrama de caja (y bigotes) o boxplot.
Este diagrama se basa en las medidas de posición, dibujando una caja en base al primer y tercer cuartil, indicando la mediana o segundo cuartil dentro de la caja. Usamos el argumento horizontal
para mostrar el boxplot “acostado”.
boxplot(titanic$Age
horizontal = TRUE) ,
Si quiero comparar distribuciones de distintos, el comando boxplot
ofrece la posibilidad de separar datos de acuerdo a una variable que indica los grupos. De esta manera, si quiero comparar las distribuciones de edad de los pasajeros en cada una de las tres clases del Titanic, puedo usar la virgulilla ~
(también conocida a veces como “cola de chancho”) para indicar de acuerdo a que grupo quiero separa la edad:
# "Genera un boxplot de la distribución de edad de acuerdo a clase"
boxplot(titanic$Age ~ titanic$Pclass)
Generando tablas de resumen con describe
Un comando alternativo para ver resúmenes de datos es el comando describe
disponible en la librería psych
. Instalemos y carguemos esta librería.
#install.packages("psych")
library(psych)
Podemos usar el comando describe
ahora para ver detalles sobre una variable.
describe(titanic$Age)
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 714 29.7 14.53 28 29.27 13.34 0.42 80 79.58 0.39 0.16 0.54
Y podemos usar el comando describeBy
(describir por) para mostrar este mismo resumen por grupos con el argumento group
.
describeBy(titanic$Age, group = titanic$Pclass)
Descriptive statistics by group
group: 1
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 186 38.23 14.8 37 37.98 16.31 0.92 80 79.08 0.12 -0.41 1.09
------------------------------------------------------------
group: 2
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 173 29.88 14 29 29.87 10.38 0.67 70 69.33 0.13 0.17 1.06
------------------------------------------------------------
group: 3
vars n mean sd median trimmed mad min max range skew kurtosis se
X1 1 355 25.14 12.5 24 24.84 10.38 0.42 74 73.58 0.48 0.94 0.66