La distribución básica de R incluye numerosas funciones para construir tablas y gráficos estadísticos. Sin embargo, si lo vas a usar habitualmente para manipulación, representación y análisis de datos puedes cargar el conjunto de paquetes tidyverse. Son 8 paquetes de R diseñados específicamente para trabajar con datos. Para cargarlos, simplemente instálalo en la pestaña Packages y cárgalo:

library(tidyverse)

De los 8 paquetes, los que más vamos a utlizar al principio son dplyrpara manipulación de datos y ggplot2 para crear gráficos más vistosos que con las funciones por defecto, aunque también aprenderemos a usar estas últimas.

dplyr tiene definidos 5 verbos para manipular los datos. Para ver cómo usar estos verbos, vamos a trabajar con un conjunto de datos que viene con la distribución del software: el conjunto mtcars. Para ver la descripción de los datos, teclea help(mtcars). El comando str nos muestra la estructura del conjunto de datos (structure) y su dimensión, es decir, el número de filas y de columnas que tiene. Este conjunto tiene estructura de data.frame la estructura básica de datos en R en la que las filas son individuos o unidades y las columnas son variables o características medidas sobre cada individuo. Vemos que todas las variables vienen declaradas como numéricas, aunque en realidad haya variables nominales, cuantitativas continuas y discretas.

data(mtcars)
help(mtcars)
dim(mtcars)
## [1] 32 11
str(mtcars)
## 'data.frame':    32 obs. of  11 variables:
##  $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
##  $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
##  $ disp: num  160 160 108 258 360 ...
##  $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
##  $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
##  $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
##  $ qsec: num  16.5 17 18.6 19.4 17 ...
##  $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
##  $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
##  $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
##  $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

Con el comando head(mtcars) vemos las primeras filas del conjunto de datos. Cada fila es un coche y cada columna una característica o variable medida sobre él. El comando siguiente usa la función kabledel paquete knitr que simplemente representa las seis primeras filas del fichero de datos de forma más ordenada y con un formato más claro. Cuando hay dos paquetes que tienen una función con el mismo nombre, forzamos a Ra que use la función de un paquete determinado con esa notación paquete::función.

knitr::kable(head(mtcars)) 
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

Las variables nominales son:

Sabemos que aunque vengan codificadas con números, estos números representan categorías. Para poder hacer uso de ellas atendiendo a su naturaleza nominal vamos a definirlas como factores. Un factor es una variable categórica que suele usarse para dividir en grupos la distribución de otra variable cuantitativa.

En el código que sigue, el símbolo $ selecciona la variable cuyo nombre se teclea a continuación del conjunto de datos cuyo nombre le precede datos$variable.

mtcars$am<-factor(mtcars$am, labels=c("automático", "manual"))
mtcars$vs<-factor(mtcars$vs, labels=c("V-engine","straight"))

Las variables cuantitativas discretas son:

Las variables cuantitativas continuas son las siguientes:

Vamos a practicar un poco con los verbos básicos de manipulación de datos: arrange, select, filter, mutatey summarise. En el código, vamos a usar el símbolo %>%. Es un pipe operator muy útil para enlazar comandos o funciones. Se lee then. Por ejemplo, 1:8 %>% sum %>% sqrt, suma los números del 1 al 8 y calcula la raíz cuadrada de la suma.

1:8 %>% sum %>% sqrt # es equivalente a
## [1] 6
sqrt(sum(1:8))
## [1] 6

arrange ordena las observaciones por el valor de una variable, por defecto, de menor a mayor valor:

knitr::kable(head(mtcars %>% arrange(cyl)))
mpg cyl disp hp drat wt qsec vs am gear carb
Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 straight manual 4 1
Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 straight automático 4 2
Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 straight automático 4 2
Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 straight manual 4 1
Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 straight manual 4 2
Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 straight manual 4 1

select selecciona un subconjunto de columnas. Voy a crear otro fichero de datos que contenga solamente las columnas mpg, cyly carb:

mi_sub<- mtcars %>% select(mpg, cyl, carb)

filterselecciona las filas que cumplan la condición dada:

mi_sub<- mtcars %>% filter(am=="automático" & cyl==6)

mutate crea nuevas variables que podemos definir a partir de las columnas que ya tenemos:

mi_sub<- mtcars %>% mutate(log_mpg=log(mpg))

También podemos crear nuevas variables categorizando una variable cuantitativa. Por ejemplo, la variable carb toma valores 1,2,3,4,6,8. Supongamos que queremos crear una variable nueva carb_n que tome el valor Bajo para los valores 1,2 y 3 y Alto en el resto:

mtcars=mtcars %>% mutate(carb_n=ifelse(carb>=4, "Alto", "Bajo"))

Comprueba que ha creado la nueva variable al final y que se corresponde con lo que queríamos. Si queremos crear una variable categórica a partir de carb pero con 3 categorías distintas, primero creo una variable factor para carb y la recodifico:

mtcars=mtcars %>% mutate(carb_f=factor(carb))
mtcars=mtcars %>% mutate(carb_c=fct_recode(carb_f, "Bajo"="1", "Bajo"="2",
 "Medio"="3", "Medio"="4", "Alto"="6", "Alto"="8"))

Comprueba con head(mtcars) que ha creado la variable que queremos.

summarise no es muy útil solo, pero cuando lo combinamos con group_byla cosa cambia. Vamos a calcular la media de la variable mpg para los coches automáticos y manuales:

mtcars %>% group_by(am) %>% summarise(count=n(),mean_mpg=mean(mpg), median=median(mpg))
## # A tibble: 2 × 4
##   am         count mean_mpg median
##   <fct>      <int>    <dbl>  <dbl>
## 1 automático    19     17.1   17.3
## 2 manual        13     24.4   22.8

Como vemos, hay 19 coches automáticos con un valor medio de mpg de \(17.14\) y 17 coches manuales para los que la variable mpg tiene una media de \(24.39\). ¿Es casualidad que la media de mpg de los coches manuales sea mayor que la de los coches automáticos? ¿O es así porque existe en realidad una diferencia en la media de esta variable entre estos dos tipos de coches? Este tipo de preguntas se resuelven con la rama de la Estadística llamada Inferencia Estadística. Una vez que analizamos los datos de una muestra y si la muestra es representativa de la población, las diferencias que observamos entre grupos, ¿son casualidad, son debidas a la aleatoriedad del muestreo? o por el contrario, ¿se deben a diferencias sistemáticas entre las variables en la población?

Ahora que ya sabemos cómo funcionan los verbos básicos de manipulación de datos, vemos cómo construir tablas de frecuencia univariantes.

Tablas univariantes

Para obtener una tablas básicas de una variable nominal u ordinal con pocos valores diferentes, o incluso una variable cuantitativa discreta, de nuevo, que tome pocos valores diferentes, usamos el comando table.

table(mtcars$am) # 19 coches automáticos y 13 manuales
## 
## automático     manual 
##         19         13
table(mtcars$cyl) # distribución básica de los cilindros
## 
##  4  6  8 
## 11  7 14

Podemos completar las tablas anteriores. Para la variable am añadimos la columna de frecuencia relativa.

am_basic_table=data.frame(table(mtcars$am)) # la tabla básica, como un data frame
colnames(am_basic_table)=c("Value","Freq") # cambio el nombre de las columnas
am_table= am_basic_table %>% mutate(Frec_rel=prop.table(am_basic_table$Freq)) # creo la columna de frecuencias relativas
am_table
##        Value Freq Frec_rel
## 1 automático   19  0.59375
## 2     manual   13  0.40625
sum(am_table$Frec_rel) # comprobamos que las frecuencias relativas suman 1
## [1] 1

Si tienes una variable cuantitativa continua que toma muchos valores diferentes, No uses el comando table. Obtendrías una tabla muy grande donde todos los valores observados tendrían frecuencia de \(1\) y no serviría de nada. Para construir la tabla de frecuencias en este caso, hay que agrupar los datos en intervalos.

# Primero, averigua el mínimo y el máximo de tus valores
min(mtcars$mpg); max(mtcars$mpg)
## [1] 10.4
## [1] 33.9
# Ahora, divido todo el recorrido de la variable en intervalos, empezando un
# poco antes del mínimo y terminando un poco después del máximo, digamos, de
# 10 a 35. Voy a usar 5 intervalos de longitud 5, del tipo [,)
cut_points_mpg=cut(mtcars$mpg, breaks=seq(10,35,by=5),right=F)
basic_table_mpg=table(cut_points_mpg)
basic_table_mpg=as.data.frame(basic_table_mpg)
colnames(basic_table_mpg)=c("Clase","FrecAbs") # basic_table_mpg es una tabla
# básica
basic_table_mpg # a la que añadiremos más columnas
##     Clase FrecAbs
## 1 [10,15)       5
## 2 [15,20)      13
## 3 [20,25)       8
## 4 [25,30)       2
## 5 [30,35)       4
Table_mpg=basic_table_mpg %>%  mutate(FrecAbsAc=cumsum(FrecAbs),FrecRel=round(prop.table(basic_table_mpg$FrecAbs),5), FreRelAc=cumsum(FrecRel))
Table_mpg
##     Clase FrecAbs FrecAbsAc FrecRel FreRelAc
## 1 [10,15)       5         5 0.15625  0.15625
## 2 [15,20)      13        18 0.40625  0.56250
## 3 [20,25)       8        26 0.25000  0.81250
## 4 [25,30)       2        28 0.06250  0.87500
## 5 [30,35)       4        32 0.12500  1.00000
  1. Construye una tabla de frecuencias para la variable hp dividiendo el rango de la variable en \(6\) intervalos que comiencen en 50 y terminen en 350. Usa intervalos abiertos por la derecha y cerrados por la izquierda.
Solución
# creamos los intervalos con sus frecuencias absolutas
cut_points_hp=cut(mtcars$hp,breaks=seq(50,350,by=50),right=F,include.lowest=TRUE)
basic_table_hp=table(cut_points_hp)
# transformo la tabla en un data.frame para añadir el resto de columnas
basic_table_hp=data.frame(basic_table_hp)
# pongo nombre a las columnas que ya tengo
colnames(basic_table_hp)=c("Clase","FrecAbs")
# añado las columnas
Table_hp=basic_table_hp %>%  mutate(FrecAbsAc=cumsum(FrecAbs),FrecRel=round(prop.table(basic_table_hp$FrecAbs),5), FreRelAc=cumsum(FrecRel))
Table_hp
##       Clase FrecAbs FrecAbsAc FrecRel FreRelAc
## 1  [50,100)       9         9 0.28125  0.28125
## 2 [100,150)       8        17 0.25000  0.53125
## 3 [150,200)       8        25 0.25000  0.78125
## 4 [200,250)       5        30 0.15625  0.93750
## 5 [250,300)       1        31 0.03125  0.96875
## 6 [300,350]       1        32 0.03125  1.00000

Tablas bivariantes

Puedes crear y manipular tablas de contingencia (tablas bivariantes de variables categóricas) usando el paquete vcd. También puedes usar el comando básico table, table(mtcars$am, mtcars$cyl).

library(vcd)
## Loading required package: grid
# con frecuencias absolutas
xtabs(~am+cyl, data=mtcars) %>% addmargins()
##             cyl
## am            4  6  8 Sum
##   automático  3  4 12  19
##   manual      8  3  2  13
##   Sum        11  7 14  32
# con frecuencias relativas
xtabs(~am+cyl, data=mtcars) %>% prop.table() %>% addmargins()
##             cyl
## am                 4       6       8     Sum
##   automático 0.09375 0.12500 0.37500 0.59375
##   manual     0.25000 0.09375 0.06250 0.40625
##   Sum        0.34375 0.21875 0.43750 1.00000

Con el comando addmargins hemos añadido la última fila y la última columna. La última fila, con el nombre de Sum representa la distribución marginal de la variable \(Y=\)cilindros y la última columna representa la distribución marginal de la variable \(X\)=tipo de transmisión. Si sobre una tabla de frecuencias absolutas usamos el comando prop.table, obtenemos la misma tabla en frecuencias relativas.

Podemos representar una tabla de contingencia con la función mosaicdel paquete vcd. En esta representación, el tamaño de cada celda es proporcional al número de observaciones en ella.

# mosaic plot
table1=xtabs(~am+cyl, data=mtcars)
mosaic(table1, gp=shading_max, split_vertical=TRUE)

Vemos claramente que la combinación con más observaciones es coches automáticos con 8 cilindros seguida de coches manuales con 4 cilindros. Los colores del mosaic plot se refieren al concepto de independencia entre las dos variables. Las variables no son independientes: hay más (color azul) observaciones en la categoría 8 y automático y en la categoría 4 y manual de las que habría si las variables fueran independientes. Hay menos (color rojo) observaciones en la categoría 4 y automático y 8 y manual de las que cabría esperar si las variables fueran indpendientes. Las celdas de color gris muestran una frecuencia absoluta cercana a la que cabría esperar si ambas variables fueran independientes.

  1. Analiza, según los colores mostrados en un mosaic plot, la independencia de las variables gear(número de marchas) y vs (tipo de motor) en el conjunto de datos mtcars.
Solución
table1=xtabs(~gear+vs, data=mtcars)
mosaic(table1, gp=shading_max, split_vertical=TRUE)

Los colores del mosaic plot muestran que las variables no son independientes. Hay menos motores V-engine con 4 marchas y menos straight con 3 marchas de lo que cabría esperar si las variables fueran independientes. De la misma forma, hay más coches de 3 marchas y V-engine y de 4 y straight de lo que cabría esperar si fueran independientes. Sin embargo, en los coches con 5 marchas las observaciones sí son compatibles con la independencia de las variables.

Medidas descriptivas de una distribución de frecuencias

Medidas características (Summary statistics) para una variable: Estas son algunas funciones útiles que puedes usar con las observaciones de una variable para calcular varias medidas descriptivas:

  • mean para la media
  • median para la mediana
  • sd para la desviación típica (standard deviation)
  • var para la varianza
  • IQR para el rango intercuartílico
  • range para el rango
  • min para el mínimo
  • max para el máximo
  • quantile para cuantiles. Por defecto, salen el mínimo, \(Q_1\), \(Q_2\), \(Q_3\) y el máximo. Para obtener unos en concreto, utiliza probs=c(0.23,0.60), por ejemplo para los percentiles \(23\) y \(60\).
quantile(mtcars$mpg, probs=c(0.23, 0.6))
##    23%    60% 
## 15.239 21.000

La función summary aplicada a un conjunto de datos devuelve:

summary(mtcars$mpg)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   10.40   15.43   19.20   20.09   22.80   33.90

Podemos calcular nosotros directamente le desviación absoluta media con respecto a la mediana. Vemos un ejemplo con la variable mpg:

mean(abs(mtcars$mpg-median(mtcars$mpg))) # con respecto a la mediana
## [1] 4.634375
mean(abs(mtcars$mpg-mean(mtcars$mpg))) # con respecto a la media
## [1] 4.714453

Vemos que, efectivamente, el mínimo de tales desviaciones se alcanza en la mediana.

Vamos a comprobar empíricamente la desigualdad de Tchebychev con la variable hp de los datos mtcars. Necesitamos la media y la desviación típica.

mean(mtcars$hp); sd(mtcars$hp) 
## [1] 146.6875
## [1] 68.56287
valores=c(mean(mtcars$hp)-2*sd(mtcars$hp),mean(mtcars$hp)+2*sd(mtcars$hp))
sum(ifelse(mtcars$hp >= valores[1] & mtcars$hp<=valores[2],1,0))
## [1] 31

En este caso, entre la media y 2 desviaciones típicas se encuentran 31 datos de 32, un \(96.8\%\). La desigualdad de Tchabychev nos dice que, como mínimo, se encuentra el \(75\%\) de los datos.

Si queremos los coeficientes de asimetría y curtosis tal y como se han definido en clase, hay que cargar el paquete e1071:

library("e1071")
skewness(mtcars$mpg)
## [1] 0.610655
kurtosis(mtcars$mpg)
## [1] -0.372766

Para calcular estadísticos descriptivos por grupos, es decir, definiendo los grupos usando una variable categórica (factor en R) podemos usar:

mtcars %>% group_by(am) %>% summarise(n=n(), mean(disp), sd(disp))
## # A tibble: 2 × 4
##   am             n `mean(disp)` `sd(disp)`
##   <fct>      <int>        <dbl>      <dbl>
## 1 automático    19         290.      110. 
## 2 manual        13         144.       87.2

Obtenemos la media y desviación típica de la variable dispen cada uno de los grupos definidos por la variable am. Podemos agrupar por dos o más variables categóricas:

mtcars %>% group_by(am, cyl) %>% summarise(n=n(), mean(disp), sd(disp))
## `summarise()` has grouped output by 'am'. You can override using the `.groups`
## argument.
## # A tibble: 6 × 5
## # Groups:   am [2]
##   am           cyl     n `mean(disp)` `sd(disp)`
##   <fct>      <dbl> <int>        <dbl>      <dbl>
## 1 automático     4     3        136.       14.0 
## 2 automático     6     4        205.       44.7 
## 3 automático     8    12        358.       71.8 
## 4 manual         4     8         93.6      20.5 
## 5 manual         6     3        155         8.66
## 6 manual         8     2        326        35.4

Así podemos ver cómo va cambiando la media, por ejemplo, de una variable cuantitativa en los distintos grupos definidos por una o varias variables categóricas.

Antes de calcular medidas de dependencia lineal entre dos variables cuantitativas, vamos a dibujar un diagrama de dispersión para ver su distribución conjunta.

ggplot(mtcars, aes(x=mpg, y=disp))+geom_point()

Vemos que los puntos se disponen, más o menos, a lo largo de una recta de pendiente negativa. A mayor valor de la variable mpg menor valor de la variable disp.

Medidas características (Summary statistics) para dos variables:

Puedes usar:

  • cov para la covarianza. Normalmente no la vamos a usar ya que calcularemos directamente el coeficiente de correlación de Pearson.
  • cor para el coeficiente de correlación de Pearson.
# covarianza y correlación entre mpg y disp
cov(mtcars$mpg, mtcars$disp)
## [1] -633.0972
cor(mtcars$mpg, mtcars$disp)
## [1] -0.8475514

Como vemos por el valor del coeficiente de correlación, la relación lineal entre mpg y disp es fuerte y negativa.