INTRODUCCIÓN

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:

Existen diferentes posibilidades para calcular esos valores desagregados según otras variables.

FUNCIÓN 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

Función aggregate
Función aggregate

Hay dos posibles ejemplos de uso de aggregate() en función de la salida que proporciona

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

FUNCIÓN 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.

Función tapply
Función tapply

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)

FUNCIÓN 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.