Introducción:

Los datos cuantitativos son los que expresan cantidades que se representan mediante números. Éstos se suelen clasificar en continuos y discretos.

Conviene tener en cuenta que esta división es solo teórica. Es decir, en la práctica, todos estos datos son discretos puesto que la precisión infinita no existe. Sin embargo, es necesario de vez en cuando suponer los datos de tipo continuo para así poder utilizar técnicas específicas en su análisis.

A la hora de estudiar variables cuantitativas, podemos utilizar las frecuencias que hemos visto hasta el momento: absoluta, relativa, acumulada y relativa acumulada. Esto se debe a que podemos ordenar los datos cuantitativos en el orden natural de los números reales.

En este caso, disponemos de muchas otras técnicas descriptivas aparte de las frecuencias, puesto que estamos trabajando con números reales y podemos operar con ellos.

Los datos cuantitativos admiten dos tipos de tratamiento según trabajemos con los raw data (datos brutos u originales) o bien los agrupemos en clases o intervalos.

En esta lección trabajaremos sobre la primera situación. En la siguiente, estudiaremos la descripción de datos cuantitativos agrupados.

Ejemplo como se trabajan las frecuencias de datos cuantitativos

El tratamiento de las frecuencias de datos cuantitativos es similar al de los datos ordinales. La cosa cambia ligeramente debido a que no se tienen en cuenta todos los niveles posibles, sino únicamente los observados.

Se han pedido las edades a 20 clientes de un museo. Las respuestas obtenidas han sido las siguientes:

# Edades de 20 clientes en un museo:
edad <- c(15,18,25,40,30,29,56,40,13,27,42,23,11,26,25,32,30,40,33,29)
# Recordemos que solamente nos interesan las frecuencias de las edades 
# observadas. Es decir, solamente nos interesan 
table(edad)
## edad
## 11 13 15 18 23 25 26 27 29 30 32 33 40 42 56 
##  1  1  1  1  1  2  1  1  2  2  1  1  3  1  1

Para datos ordinales solo se estudian las variables observadas, no hay niveles como cuando hacemos un análisis de datos cualitativos. Podemos calcular el resto de frecuencias:

# frecuencias relativas
round(prop.table(table(edad)),3)
## edad
##   11   13   15   18   23   25   26   27   29   30   32   33   40   42   56 
## 0.05 0.05 0.05 0.05 0.05 0.10 0.05 0.05 0.10 0.10 0.05 0.05 0.15 0.05 0.05
# frecuancias acumuladas
cumsum(table(edad))
## 11 13 15 18 23 25 26 27 29 30 32 33 40 42 56 
##  1  2  3  4  5  7  8  9 11 13 14 15 18 19 20
# tabla de frecuencias relativa acumulada
round(cumsum(prop.table(table(edad))),3)
##   11   13   15   18   23   25   26   27   29   30   32   33   40   42   56 
## 0.05 0.10 0.15 0.20 0.25 0.35 0.40 0.45 0.55 0.65 0.70 0.75 0.90 0.95 1.00

Un ejemplo con notación matemática

En general, supongamos que tenemos \(n\) observaciones de una propiedad que se mide con un número real y obtenemos la variable cuantitativa formada por los datos \[x_1,\dots, x_n\]

Sean ahora \(X_1,\dots,X_k\) los valores distintos que aparecen en esta lista de datos y considerémoslos ordenados \[X_1<X_2<\cdots<X_k\]

Entonces, en esta variable cuantitativa

  • La frecuencia absoluta de \(X_i\) es el número \(n_i\) de elementos que son iguales a \(X_i\)
  • La frecuencia relativa de \(X_i\) es \(f_i=\frac{n_i}{n}\)
  • La frecuencia absoluta acumulada de \(X_i\) es \(N_i=\sum_{j=1}^in_j\)
  • La frecuencia relativa acumulada de \(X_i\) es \(F_i=\frac{N_i}{n}\)m

Creemos un ejemplo:

Lanzamos 25 veces un dado de 6 caras y anotamos las puntuaciones obtenidas en cada tirada.

En este caso, \(n=25\) y, los distintos valores observados son

\[X_1 = 1,\ X_2 = 2,\ X_3 = 3,\ X_4 = 4,\ X_5 = 5,\ X_6 = 6\]

Nos interesa ahora calcular las frecuencias de este experimento. Además, las organizaremos en un data frame para observarlas de forma más clara y sencilla en una tabla.

set.seed(162017)
dados <- sample(1:6, 25, replace = TRUE)
dados
##  [1] 6 6 6 1 2 3 2 5 1 3 2 4 1 2 2 6 3 6 3 5 3 1 3 2 4
# tabla de frecuencas absolutas
table(dados)
## dados
## 1 2 3 4 5 6 
## 4 6 6 2 2 5
# frecuencias absolutas relativas
round(prop.table(table(dados)),2)
## dados
##    1    2    3    4    5    6 
## 0.16 0.24 0.24 0.08 0.08 0.20
# tabla de frecuencias acumuladas
cumsum(table(dados))
##  1  2  3  4  5  6 
##  4 10 16 18 20 25
# tabla de frecuencias relativas acumuladas
round(cumsum(prop.table(table(dados))),2)
##    1    2    3    4    5    6 
## 0.16 0.40 0.64 0.72 0.80 1.00

ATTENTION para entrar una tabla unidimensional como un avaribale en un data frame, es conveniente transformarla en un vector con as.vector. Si no, cada table y cada prop.tableañadirían una columna extra con los nombres de los niveles.

round(cumsum(prop.table(table(dados))),2)
##    1    2    3    4    5    6 
## 0.16 0.40 0.64 0.72 0.80 1.00
dados.df = data.frame(Puntuacion = 1:6,
                      Fr.abs = as.vector(table(dados)),
                      Fr.rel = as.vector(round(prop.table(table(dados)),2)),
                      Fr.acu = as.vector(cumsum(table(dados))),
                      Fr.racu = as.vector(round(cumsum(prop.table(table(dados))),2)))

¡OJO! Para entrar una tabla unidimensional como una variable en un data frame, es conveniente transformarla en vector con as.vector. Si no, cada table y cada prop.table añadirían una columna extra con los nombres de los niveles.

Medidas de tendecia central

Son las que dan un valor representativo a todas las observaciones. Algunas de las más importantes son:

La mediana

La definición formal de la mediana es la siguiente. Denotando por \[x_{(1)}\le x_{(2)}\le\dots\le x_{(n)}\] los datos de la variable cuantitativa ordenados de menor a mayor, la mediana es

  • Si \(n\) par, la medio de los dos datos centrales \[\frac{x_{(\frac{n}{2})}+x_{(\frac{n}{2}+1)}}{2}\]
  • Si \(n\) impar, el dato central \(x_{(\frac{n+1}{2})}\)

Ejemplo 1

Recordemos el ejemplo de las edades.

# Ordenar de mayor a menor
sort(edad)
##  [1] 11 13 15 18 23 25 25 26 27 29 29 30 30 32 33 40 40 40 42 56
# detectando estadísticos de centralización
table(edad)
## edad
## 11 13 15 18 23 25 26 27 29 30 32 33 40 42 56 
##  1  1  1  1  1  2  1  1  2  2  1  1  3  1  1

En este caso, la moda es 40, la mediana es \(\frac{29+29}{2}=29\) y la media aritmética es \[\frac{11+13+15+18+23+25+25+26+27+29+29+30+30+32+33+40+40+40+42+56}{20}=29.2\] ### Ejemplo 2

Recordemos el ejemplo de los dados.

dados.df
##   Puntuacion Fr.abs Fr.rel Fr.acu Fr.racu
## 1          1      4   0.16      4    0.16
## 2          2      6   0.24     10    0.40
## 3          3      6   0.24     16    0.64
## 4          4      2   0.08     18    0.72
## 5          5      2   0.08     20    0.80
## 6          6      5   0.20     25    1.00

En este caso, la moda son dos valores: el 2 y el 3. La mediana es \(x_{(13)}=\) 3 y la media aritmética es 3.28

Vamos a calcular la media aritmética, mediana y moda de los dos ejemplos anteriores con instrucciones de R.

# calculando con R
mean(edad) #La media aritmética
## [1] 29.2
mean(dados)
## [1] 3.28
median(edad) #La mediana
## [1] 29

U otra forma de calcularlo:

median(dados)
## [1] 3
as.numeric(names(which(table(edad)==max(table(edad))))) #La moda
## [1] 40
as.numeric(names(which(table(dados)==max(table(dados)))))
## [1] 2 3

Las diferentes medias en matemáticas

Vamos a crear un vector de datos para trabajar:

x <- c(32, 45, 67, 43, 28, 17, 48, 95)
n <- length(x)
  1. Media aritmética: promedio de un conjunto de valores o de su distribución. Va a tomar los valores y va dividirlo:

\[\bar{x} = \frac{1}{n}\sum_{i=1}^n x_i\]

# Media aritmética
sum(x)/n
## [1] 46.875
mean(x)
## [1] 46.875
  1. Media aritmética ponderada

Es una forma de generalizar la media aritmética. Otorgamos valores a los datos dependiendo del peso de los datos en el estudio.

\[\bar{x}_W = \frac{\sum_{i=1}^nw_i\cdot x_i}{\sum_{i=1}^n w_i}\]

Primero definimos los pesos:

w <- c(1, 2, 2, 3, 3, 2, 2, 1)
sum(w*x)/sum(w)
## [1] 43.375
  1. Media geométrica

Es un promedio muy útil cuando en conjuntos de números que son interpretados en orden de su producto, no de suma.

\[\bar{x}_G = \left(\prod_{i^1}^n x_i\right)^{1/n}\]

Implementamos en R:

prod(x)^(1/n)
## [1] 41.62073
prod(x^(1/n))
## [1] 41.62073
  1. Media armónica

Muy útil en conjunto de números que se definen en relación con alguna unidad, por ejemplo, la velocidad.

\[\bar{x}_A = \frac{n}{\sum_{i=1}^{n}\frac{1}{x_i}}\]

n/sum(1/x)
## [1] 36.77301

Medidas de posición

Estos valores son los que dividen las observaciones en unas determinadas proporciones. Los valores que determinan estas posiciones son conocidos como los cuantiles. Por ejemplo, la mediana seria el cuantil 0.5. Veamos un ejemplo:

set.seed(260798)
dado <- sample(1:4, 50, replace = TRUE)
set.seed(NULL)
length(dado)
## [1] 50

Veamos los resultados:

dado <- sort(dado)
dado
##  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3
## [36] 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4

Recordemos que podemos ver la tabla de frecuencias:

df.dado <- data.frame(Punctuation = 1:4, 
                      Fr.abs = as.vector(table(dado)),
                      Fr.rel = as.vector(round(prop.table(table(dado)),2)),
                      Fr.acu = as.vector(cumsum(table(dado))),
                      Fr.racu = as.vector(round(cumsum(prop.table(table(dado))),2)))
df.dado
##   Punctuation Fr.abs Fr.rel Fr.acu Fr.racu
## 1           1     19   0.38     19    0.38
## 2           2     14   0.28     33    0.66
## 3           3      9   0.18     42    0.84
## 4           4      8   0.16     50    1.00

Si queremos ver el ver el quantil 0.3 nos podríamos fijarnos el la frecuencia relativa acumulada cuando sobrepase a 0.3 para detectar el cuantil. También podríamos mirarlo de la siguiente forma:

dado[15]
## [1] 1

Los cuantiles tienen nombres propios:

Miremos un ejemplo:

set.seed(0)
dados2 <- sample(1:6, 15, replace = T)
dados2
##  [1] 6 2 3 4 6 2 6 6 4 4 1 2 2 5 3
set.seed(NULL)
quantile(dados2, 0.25)
## 25% 
##   2
quantile(dados2, 0.8)
## 80% 
##   6

Medidas de dispersión

miden como de dispersos están los datos. Los más importantes són:

Como calcular medidas de dispersión en R

  • Valores mínimo y mádados2imo
range(dados2)
## [1] 1 6
  • Rango (diferencia entre el mádados2imo y el mínimo)
diff(range(dados2))
## [1] 5
  • Rango intercuartílico
IQR(dados2, type = 7)
## [1] 3.5
  • Varianza muestral
var(dados2)
## [1] 3.066667
  • Desviación típica muestral
sd(dados2)
## [1] 1.75119
  • Varianza
var(dados2)*(length(dados2)-1)/length(dados2)
## [1] 2.862222
  • Desviación típica
sd(dados2)*sqrt((length(dados2)-1)/length(dados2))
## [1] 1.69181

Agregar datos cuantitativos por factor

cangrejos <-  read.table("data/datacrab.txt", header = T)
cangrejos <- cangrejos[-1]
summary(cangrejos)
##      color           spine           width          satell      
##  Min.   :2.000   Min.   :1.000   Min.   :21.0   Min.   : 0.000  
##  1st Qu.:3.000   1st Qu.:2.000   1st Qu.:24.9   1st Qu.: 0.000  
##  Median :3.000   Median :3.000   Median :26.1   Median : 2.000  
##  Mean   :3.439   Mean   :2.486   Mean   :26.3   Mean   : 2.919  
##  3rd Qu.:4.000   3rd Qu.:3.000   3rd Qu.:27.7   3rd Qu.: 5.000  
##  Max.   :5.000   Max.   :3.000   Max.   :33.5   Max.   :15.000  
##      weight    
##  Min.   :1200  
##  1st Qu.:2000  
##  Median :2350  
##  Mean   :2437  
##  3rd Qu.:2850  
##  Max.   :5200

Imaginemos que nos queremos centrat en comparar ciertas variables de 3 colores:

summary(subset(cangrejos, color == 3, c("weight", "width")))
##      weight         width     
##  Min.   :1300   Min.   :22.5  
##  1st Qu.:2100   1st Qu.:25.1  
##  Median :2500   Median :26.5  
##  Mean   :2538   Mean   :26.7  
##  3rd Qu.:3000   3rd Qu.:28.2  
##  Max.   :5200   Max.   :33.5

Podemos usar la función by() para aplicar una función determinada a ciertas columnas. Así podemos obtener el resumen estadístico en relación a cada especie:

by(iris[,c(1,3)], iris$Species, FUN = summary)
## iris$Species: setosa
##   Sepal.Length    Petal.Length  
##  Min.   :4.300   Min.   :1.000  
##  1st Qu.:4.800   1st Qu.:1.400  
##  Median :5.000   Median :1.500  
##  Mean   :5.006   Mean   :1.462  
##  3rd Qu.:5.200   3rd Qu.:1.575  
##  Max.   :5.800   Max.   :1.900  
## -------------------------------------------------------- 
## iris$Species: versicolor
##   Sepal.Length    Petal.Length 
##  Min.   :4.900   Min.   :3.00  
##  1st Qu.:5.600   1st Qu.:4.00  
##  Median :5.900   Median :4.35  
##  Mean   :5.936   Mean   :4.26  
##  3rd Qu.:6.300   3rd Qu.:4.60  
##  Max.   :7.000   Max.   :5.10  
## -------------------------------------------------------- 
## iris$Species: virginica
##   Sepal.Length    Petal.Length  
##  Min.   :4.900   Min.   :4.500  
##  1st Qu.:6.225   1st Qu.:5.100  
##  Median :6.500   Median :5.550  
##  Mean   :6.588   Mean   :5.552  
##  3rd Qu.:6.900   3rd Qu.:5.875  
##  Max.   :7.900   Max.   :6.900

La functión aggregate() son equivalentes. No obstante los resultados se muestran de forma diferente:

aggregate(cbind(Sepal.Length, Petal.Length)~Species, 
          data = iris, FUN = summary)
##      Species Sepal.Length.Min. Sepal.Length.1st Qu. Sepal.Length.Median
## 1     setosa             4.300                4.800               5.000
## 2 versicolor             4.900                5.600               5.900
## 3  virginica             4.900                6.225               6.500
##   Sepal.Length.Mean Sepal.Length.3rd Qu. Sepal.Length.Max.
## 1             5.006                5.200             5.800
## 2             5.936                6.300             7.000
## 3             6.588                6.900             7.900
##   Petal.Length.Min. Petal.Length.1st Qu. Petal.Length.Median
## 1             1.000                1.400               1.500
## 2             3.000                4.000               4.350
## 3             4.500                5.100               5.550
##   Petal.Length.Mean Petal.Length.3rd Qu. Petal.Length.Max.
## 1             1.462                1.575             1.900
## 2             4.260                4.600             5.100
## 3             5.552                5.875             6.900

Diagrama de caja

Ayuda a resumir los datos de una variable cuantitativa

boxplot(cangrejos[-5])

Configuración de los diagramas de cajas y bigotes

body <- read.table("data/bodyfat.txt", header = T)
boxplot(body)

Podemos hacer una selección de los diagramas de caja para diferentes nivels dentro de un vector de categorías:

boxplot(circumference ~ Tree, data = Orange, 
        ylab = "Cirfunferencia del tronto (mm)", 
        main = "Boxplot de los naranjos en función del tipo de árbol")

Podemos usar el parámetro boxplot(..., notch = TRUE) dentro de un boxplot para añadir un amuesca en la mediana de la caja. Si se da el caso en que las muescas de los dos diagramas de cajas no se solapan, entonces con alto grado de confianza, concluimos que las medianas de las poblaciones correspondientes son diferentes:

boxplot(weight ~ color, data = cangrejos, ylab = "Anchura del sétalo (cm)", 
        notch = TRUE)

# podemos ver que las muescas en la mediana no se solapan. Por lo tanto podemos confirmar que provienen de diferentes poblaciones. 

Podemos añadir la media aritmética:

medias <- aggregate(weight ~ color, data = cangrejos, FUN = mean)
medias
##   color   weight
## 1     2 2629.167
## 2     3 2537.811
## 3     4 2299.250
## 4     5 2173.864

Y añadirlas en el boxplot:

boxplot(weight ~ color, data = cangrejos, ylab = "Anchura del sétalo (cm)", 
        notch = TRUE)
points(medias, col = "darkgreen", pch = 15)

Podemos consultar la estructura interna de un boxplot para sacar toda la información que queramos:

str(boxplot(circumference ~ Tree, data = Orange))

## List of 6
##  $ stats: num [1:5, 1:5] 30 63 108 127 140 30 72.5 115 131 145 ...
##  $ n    : num [1:5] 7 7 7 7 7
##  $ conf : num [1:2, 1:5] 69.8 146.2 80.1 149.9 69.5 ...
##  $ out  : num(0) 
##  $ group: num(0) 
##  $ names: chr [1:5] "3" "1" "5" "2" ...

Por ejemplo, tenemos stats que nos devuelve los valores inf, Q0.25, Q0.5, Q0.75 and sup.

O obtener los outliers con out. En caso de haber diversos diagramas en un plot, la componente group nos indica a qué diagrama pertenecen estos outliers.

Podemos sacar la información de la siguiente manera:

boxplot(weight ~ color, data = cangrejos, ylab = "Anchura del sétalo (cm)")$out

## [1] 5200

Casos reales

Vamos a trabajar ccon un ejercicio de insecticida de la libreria datasets. ¿Cuál es el mejor insecticida?

library(datasets)
?InsectSprays
## starting httpd help server ... done
head(InsectSprays)
##   count spray
## 1    10     A
## 2     7     A
## 3    20     A
## 4    14     A
## 5    14     A
## 6    12     A
data <- InsectSprays

Vamos a obtener un resumen estadístico de los diferentes insecticidas:

by(data$count, data$spray, FUN = summary)
## data$spray: A
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    7.00   11.50   14.00   14.50   17.75   23.00 
## -------------------------------------------------------- 
## data$spray: B
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    7.00   12.50   16.50   15.33   17.50   21.00 
## -------------------------------------------------------- 
## data$spray: C
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.000   1.000   1.500   2.083   3.000   7.000 
## -------------------------------------------------------- 
## data$spray: D
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.000   3.750   5.000   4.917   5.000  12.000 
## -------------------------------------------------------- 
## data$spray: E
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    1.00    2.75    3.00    3.50    5.00    6.00 
## -------------------------------------------------------- 
## data$spray: F
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    9.00   12.50   15.00   16.67   22.50   26.00

Parece que los sprays A, B y F tienen pinta de matar muchos insectos, pero parece que el rango de estos sprays es superior a los otros. Puede que los sprays C, D y F son más efectivos, tienen menos variabilidad.

Para probar esta hipótesis podríamos calcular la variabilidad para cada uno de ellos:

aggregate(count ~ spray, data = data, FUN = sd)
##   spray    count
## 1     A 4.719399
## 2     B 4.271115
## 3     C 1.975225
## 4     D 2.503028
## 5     E 1.732051
## 6     F 6.213378

Parece que estábamos en lo cierot en nuestro análisis. Visualizemos nuestros resultados:

boxplot(count ~ spray, data = data, col = "lightgreen", 
        xlab = "Tipo de spray", ylab = "Insectos muertos")