En muchas ocasiones es necesario calcular un determinado estadístico en función de una o varias variables, con el fin de poder establecer comparaciones entre esos subconjuntos. Por ejemplo, imaginemos la siguiente una base de datos. En primer lugar, generaremos la base de datos con esas variables.
⚠️ ESTABLECER SEMILLA:
Para que los resultados de algunos cálculos sean idénticos a los mostrados en la página web, es necesario iniciar cada actividad estableciendo una semilla que asegure su reproducibilidad.
set.seed(123)
dataset <- data.frame(contaminante = round(rnorm(100, sd = 10, mean = 30)),
estacion = sample(c("invierno","primavera","verano", "otoño"), size = 100, replace = TRUE),
localidad = sample(paste("localidad", 1:4),
size = 100,
replace = TRUE))
head(dataset)
## contaminante estacion localidad
## 1 24 primavera localidad 2
## 2 28 primavera localidad 2
## 3 46 otoño localidad 1
## 4 31 invierno localidad 2
## 5 31 otoño localidad 1
## 6 47 otoño localidad 1
str(dataset)
## 'data.frame': 100 obs. of 3 variables:
## $ contaminante: num 24 28 46 31 31 47 35 17 23 26 ...
## $ estacion : chr "primavera" "primavera" "otoño" "invierno" ...
## $ localidad : chr "localidad 2" "localidad 2" "localidad 1" "localidad 2" ...
Esta base de datos contiene las siguiente variables:
Valores de contaminación.
Estación del año.
Localidad en la que están situadas esas estaciones.
Existen diferentes posibilidades para calcular esos valores desagregados según otras variables.
aggregate()
La función aggregate()
calcula resúmenes estadísticos
para subconjuntos de datos, que devuelve en forma de dataframe. Su
sintaxis es muy sencilla
Hay dos posibles ejemplos de uso de aggregate()
en
función de la salida que proporciona
En el caso de utilizar el argumento by
, para ver los
resultados deberemos crear siempre un objeto, que será un
dataframe.
En el caso de aplicar una fórmula con la sintaxis
variable numérica ~ variable categórica
, que evita escribir
el nombre completo de las variables, debe incluir a cambio el argumento
data
. Proporciona en pantalla un dataframe, que podemos o
no convertir en objeto.
Por ejemplo, para el cálculo de la concentracion de contaminantes según la estación del año.
promedio_estacional <- aggregate(dataset$contaminante,
by = list(dataset$estacion), # Variable categórica.
mean) # Función (estadístico).
promedio_estacional
## Group.1 x
## 1 invierno 29.56250
## 2 otoño 34.04000
## 3 primavera 30.54167
## 4 verano 29.63158
colnames(promedio_estacional) <- c("estación del año", "Promedio del contaminante")
promedio_estacional
## estación del año Promedio del contaminante
## 1 invierno 29.56250
## 2 otoño 34.04000
## 3 primavera 30.54167
## 4 verano 29.63158
La segunda opción nos puede servir para calcular el promedio de la concentración de contaminantes según la localidad.
contaminante_localidad <- aggregate(contaminante ~ localidad,
data = dataset,
FUN = mean)
contaminante_localidad
## localidad contaminante
## 1 localidad 1 29.86486
## 2 localidad 2 30.28000
## 3 localidad 3 31.45000
## 4 localidad 4 33.44444
Si quisiéramos calcular los deciles extremos la sintaxis sería la siguiente:
deciles_extremos <- aggregate(contaminante ~ localidad,
data = dataset,
FUN = quantile,
probs = c(0.05, 0.95))
También es posible la agregación simultánea. Hay varias posibilidades:
aggregate(cbind(dataset$contaminante, dataset$estacion),
by = list(dataset$localidad),
mean,
na.rm=TRUE)
## Group.1 V1 V2
## 1 localidad 1 NA NA
## 2 localidad 2 NA NA
## 3 localidad 3 NA NA
## 4 localidad 4 NA NA
aggregate(cbind(contaminante, estacion) ~ localidad,
FUN = mean,
data = dataset,
na.rm=TRUE)
## localidad contaminante estacion
## 1 localidad 1 NA NA
## 2 localidad 2 NA NA
## 3 localidad 3 NA NA
## 4 localidad 4 NA NA
media_2_factores <- aggregate(dataset$contaminante,
by = list(dataset$estacion, dataset$localidad),
FUN = mean,
na.rm=TRUE)
diferentes_estadisticos <- aggregate(dataset$contaminante,
by = list(dataset$estacion, dataset$localidad),
function(x) c(Suma = sum(x), Media = mean(x), SD = sd(x)))
aggregate(contaminante ~ estacion + localidad,
data = dataset,
FUN = mean,
na.rm=TRUE)
## estacion localidad contaminante
## 1 invierno localidad 1 30.70000
## 2 otoño localidad 1 31.61538
## 3 primavera localidad 1 28.00000
## 4 verano localidad 1 27.50000
## 5 invierno localidad 2 26.12500
## 6 otoño localidad 2 41.00000
## 7 primavera localidad 2 28.70000
## 8 verano localidad 2 35.80000
## 9 invierno localidad 3 26.57143
## 10 otoño localidad 3 39.66667
## 11 primavera localidad 3 33.87500
## 12 verano localidad 3 26.50000
## 13 invierno localidad 4 34.85714
## 14 otoño localidad 4 34.14286
## 15 primavera localidad 4 31.50000
## 16 verano localidad 4 28.00000
tapply()
Esta función también permite aplicar una función a una matriz, array o data frame calculando estadísticos, pero no sólo por filas, sino también por columas.
La clave consiste en configurar el argumento MARGIN, que puede tomar los valores 1 (por columnas), 2 ( por filas) o c(1, 2) por filas y columnas.
Primero, debemos convertir cada variable en un vector y además transformaremos las columna estación en factor, para que los nombres de los niveles se muestren en la salida de la función cuando se ejecute.
contaminante <- dataset$contaminante
localidad<- dataset$localidad
estacion <- factor(dataset$estacion,
levels = c(1, 2, 3, 4),
labels = c("invierno", "primavera", "verano", "otoño"))
Precio medio por tipo de producto
contaminación_tapply <- tapply(contaminante,
localidad,
mean)
contaminación_tapply
## localidad 1 localidad 2 localidad 3 localidad 4
## 29.86486 30.28000 31.45000 33.44444
Si es necesario se puede acceder a cada elemento de la salida especificando el índice deseado entre corchetes.
contaminación_tapply[2]
## localidad 2
## 30.28
El formato de salida puede ser algo diferente (una lista) en caso de
establecer el argumento simplify
como FALSE.
contaminación_tapply <- tapply(contaminante, localidad, mean, simplify = FALSE)
contaminación_tapply
## $`localidad 1`
## [1] 29.86486
##
## $`localidad 2`
## [1] 30.28
##
## $`localidad 3`
## [1] 31.45
##
## $`localidad 4`
## [1] 33.44444
Y en este caso, para acceder a cualquier elemento de la salida hay que utilizar el signo $ y el nombre del elemento.
contaminación_tapply$`localidad 4`
## [1] 33.44444
Finalmente, hay también que tener cuidado con la inclusión de valores NA en nuestros datos. Vamos a simular qué pasa cuando incluimos este tipo de datos. Vamos a crear un nuevo dataset e incluiremos algunos datos ausentes
dataset_NA <- as.data.frame(cbind(contaminante, estacion, localidad))
dataset_NA$contaminante <- as.numeric(dataset_NA$contaminante)
dataset_NA$estacion <- as.integer(dataset_NA$estacion)
str(dataset_NA)
## 'data.frame': 100 obs. of 3 variables:
## $ contaminante: num 24 28 46 31 31 47 35 17 23 26 ...
## $ estacion : int NA NA NA NA NA NA NA NA NA NA ...
## $ localidad : chr "localidad 2" "localidad 2" "localidad 1" "localidad 2" ...
dataset_NA[1, 1] <- NA # Añadiendo valores NA: fila 1, columna 1.
dataset_NA[2, 3] <- NA # Añadiendo valores NA: fila 2, columna 3.
dataset_NA
## contaminante estacion localidad
## 1 NA NA localidad 2
## 2 28 NA <NA>
## 3 46 NA localidad 1
## 4 31 NA localidad 2
## 5 31 NA localidad 1
## 6 47 NA localidad 1
## 7 35 NA localidad 2
## 8 17 NA localidad 3
## 9 23 NA localidad 1
## 10 26 NA localidad 3
## 11 42 NA localidad 4
## 12 34 NA localidad 1
## 13 34 NA localidad 2
## 14 31 NA localidad 1
## 15 24 NA localidad 4
## 16 48 NA localidad 2
## 17 35 NA localidad 2
## 18 10 NA localidad 2
## 19 37 NA localidad 3
## 20 25 NA localidad 1
## 21 19 NA localidad 1
## 22 28 NA localidad 4
## 23 20 NA localidad 1
## 24 23 NA localidad 1
## 25 24 NA localidad 4
## 26 13 NA localidad 3
## 27 38 NA localidad 1
## 28 32 NA localidad 2
## 29 19 NA localidad 1
## 30 43 NA localidad 2
## 31 34 NA localidad 4
## 32 27 NA localidad 2
## 33 39 NA localidad 1
## 34 39 NA localidad 1
## 35 38 NA localidad 1
## 36 37 NA localidad 1
## 37 36 NA localidad 4
## 38 29 NA localidad 3
## 39 27 NA localidad 1
## 40 26 NA localidad 1
## 41 23 NA localidad 1
## 42 28 NA localidad 2
## 43 17 NA localidad 2
## 44 52 NA localidad 3
## 45 42 NA localidad 2
## 46 19 NA localidad 3
## 47 26 NA localidad 1
## 48 25 NA localidad 1
## 49 38 NA localidad 4
## 50 29 NA localidad 1
## 51 33 NA localidad 1
## 52 30 NA localidad 1
## 53 30 NA localidad 4
## 54 44 NA localidad 3
## 55 28 NA localidad 1
## 56 45 NA localidad 4
## 57 15 NA localidad 1
## 58 36 NA localidad 3
## 59 31 NA localidad 3
## 60 32 NA localidad 4
## 61 34 NA localidad 2
## 62 25 NA localidad 1
## 63 27 NA localidad 1
## 64 20 NA localidad 1
## 65 19 NA localidad 2
## 66 33 NA localidad 1
## 67 34 NA localidad 2
## 68 31 NA localidad 1
## 69 39 NA localidad 4
## 70 51 NA localidad 1
## 71 25 NA localidad 3
## 72 7 NA localidad 3
## 73 40 NA localidad 2
## 74 23 NA localidad 2
## 75 23 NA localidad 1
## 76 40 NA localidad 3
## 77 27 NA localidad 4
## 78 18 NA localidad 1
## 79 32 NA localidad 1
## 80 29 NA localidad 2
## 81 30 NA localidad 1
## 82 34 NA localidad 2
## 83 26 NA localidad 2
## 84 36 NA localidad 2
## 85 28 NA localidad 2
## 86 33 NA localidad 4
## 87 41 NA localidad 4
## 88 34 NA localidad 4
## 89 27 NA localidad 4
## 90 41 NA localidad 3
## 91 40 NA localidad 4
## 92 35 NA localidad 3
## 93 32 NA localidad 3
## 94 24 NA localidad 3
## 95 44 NA localidad 1
## 96 24 NA localidad 3
## 97 52 NA localidad 3
## 98 45 NA localidad 3
## 99 28 NA localidad 4
## 100 20 NA localidad 2
Si queremos calcular el valor medio de la contaminación según estaciones astronómicas
tapply(dataset_NA$contaminante, dataset_NA$estacion, mean)
## logical(0)
Dentro de la función tapply se pueden especificar argumentos
adicionales de la función que estás aplicando después del argumento
FUN
. En este caso, la función mean
permite
especificar el argumento na.rm
para que no tome en cuenta
esos valores NA. Este argumento por defecto es FALSE.
tapply(dataset_NA$contaminante,
dataset_NA$estacion,
mean,
na.rm = TRUE)
## logical(0)
by()
Por último, esta función se puede aplicar a un dataframe separando los resultados según un factor.
contaminante_by <- by(dataset$contaminante,
dataset$localidad,
FUN=summary,
na.rm = TRUE)
contaminante_by
## dataset$localidad: localidad 1
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 15.00 23.00 29.00 29.86 34.00 51.00
## ------------------------------------------------------------
## dataset$localidad: localidad 2
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 10.00 26.00 31.00 30.28 35.00 48.00
## ------------------------------------------------------------
## dataset$localidad: localidad 3
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 7.00 24.00 31.50 31.45 40.25 52.00
## ------------------------------------------------------------
## dataset$localidad: localidad 4
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 24.00 28.00 33.50 33.44 38.75 45.00
El mayor inconveniente: hay que transformarlos en un dataframe para exportarlos. Para ello podemos recurrir a la siguiente sintaxis:
contaminante_by <- do.call(rbind, contaminante_by)
contaminante_by
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## localidad 1 15 23 29.0 29.86486 34.00 51
## localidad 2 10 26 31.0 30.28000 35.00 48
## localidad 3 7 24 31.5 31.45000 40.25 52
## localidad 4 24 28 33.5 33.44444 38.75 45
📝 ACTIVIDAD DE EVALUACIÓN CONTINUA:
EJERCICIO 1. A partir del dataframe zonas_verdes
calcula:
El número total de parques en cada barrio
La superficie media, la superficie mediana, los percentiles 25 y 75, la desviación típica y el coeficiente de variación de la superficie según barrios.
El número máximo y mínimo de parques en obras/sin obras según barrio.
EJERCICIO 2. A partir del dataframe airquality
calcula
el valor medio mensual de las variables Temp
,
Ozone
, Solar.R
y Wind
.