Los datos cuantitativos son los que expresan cantidades que se representan mediante números. Éstos se suelen clasificar en continuos y discretos.
Los datos continuos son los que, si existiese la posibilidad de medirlos con precisión infinita, en principio podrían tomar todos los valores de un intervalo de la recta real. A modo de ejemplo, el peso, la altura, el tiempo… son datos de este tipo.
Por su parte, los datos discretos son los que pueden tomar un solo conjunto contable de valores. El número de colores de un gato, el número de individuos que conforman una población son algunos ejemplos de este tipo de datos.
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.
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
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
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.
Son las que dan un valor representativo a todas las observaciones. Algunas de las más importantes son:
La media aritmética o valor medio \[\bar{x} = \frac{\sum_{i=1}^nx_i}{n}=\frac{\sum_{j=1}^kn_jX_j}{n}=\sum_{j=1}^kf_jX_j\]
La mediana, que representa el valo central en la lista ordenada de observaciones
La moda es el valor (o valores) de máxima frecuencia (absoluta o relativa, el resultado será el mismo)
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
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
Vamos a crear un vector de datos para trabajar:
x <- c(32, 45, 67, 43, 28, 17, 48, 95)
n <- length(x)
\[\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
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
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
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
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
miden como de dispersos están los datos. Los más importantes són:
range(dados2)
## [1] 1 6
diff(range(dados2))
## [1] 5
IQR(dados2, type = 7)
## [1] 3.5
var(dados2)
## [1] 3.066667
sd(dados2)
## [1] 1.75119
var(dados2)*(length(dados2)-1)/length(dados2)
## [1] 2.862222
sd(dados2)*sqrt((length(dados2)-1)/length(dados2))
## [1] 1.69181
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
Ayuda a resumir los datos de una variable cuantitativa
boxplot(cangrejos[-5])
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
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")