28 abr 2022

Funciones vectorizadas en R: tapply

Las funciones vectorizadas en R permiten resumir un conjunto de tareas repetitivas, con algún patrón o secuencia común, o aplicar una operación a un conjunto de elementos. En la presente entrada mostramos algunos ejemplos de cómo usar la función tapply en R, esta permite crear variables por alguna condición agrupada, o collapse de base de datos.

En primer lugar, generamos una base aleatoria:

 set.seed(1)
 
my_datos <- data.frame(
              provincia = sample(c("Ocoa","Azua"), size = 10, replace = TRUE),
              ingreso = round(rnorm(10, sd = 30, mean = 100)),
              edad = round(rnorm(10, sd = 6, mean = 20)))
my_datos
 
  provincia ingreso edad
1       Ocoa      75   20
2       Azua     115   20
3       Ocoa     122   26
4       Ocoa     117   25
5       Azua      91   24
6       Ocoa     145   26
7       Ocoa     112   25
8       Ocoa      81   20
9       Azua      34    8
10      Azua     134   24

 1.1.   Collapse de base de datos

 La función tapply permite realizar operaciones agregadas a partir de alguna clase o característica indicada por alguna variable. Un ejemplo de esta son los promedios condicionados o promedios por grupo.

 tapply(my_datos$ingreso, my_datos$provincia, mean)
Azua     Ocoa
 93.5000 108.6667

También, podemos utilizar funciones propias. Esto sirve para personalizar las operaciones que queremos realizar, sin que necesariamente dependamos de las funcione pre establecidas en R. Un ejemplo de esto es calcular el coeficiente de variación por provincia:

tapply(my_datos$ingreso, my_datos$provincia, function(x) 100*sd(x)/mean(x))
    Azua     Ocoa
46.41021 24.26844

Otro ejemplo es calcular el porcentaje de personas con ingresos por debajo del promedio en cada provincia, que en nuestro ejemplo es de 102.6. Siempre que se esté probando alguna función nueva, es recomendado validar los resultados obtenidos con algunos cálculos manuales, para evitar estar cometiendo algún error de semántica:

tapply(my_datos$ingreso, my_datos$provincia, function(x) mean(x<mean(x))*100)
    Azua     Ocoa
50.00000 33.33333

 1.2.   Variables agregadas

Note usted que la secuencia anterior se ha realizado un collapse de los datos, por lo que, tenemos tantas observaciones como categorías de variable cualitativas contemos (provincias), sin embargo, en muchas ocasiones ameritamos contar con un estadístico para cada una de las variables, es decir, crear una nueva variable con una observación para individuo. Esta observación corresponde al dato agregado. Para esto utilizamos la indexación, mediante el argumento as.character, en la función tapply:

tapply(my_datos$ingreso, my_datos$provincia, mean)[as.character(my_datos$provincia)]
 
   Ocoa     Azua     Ocoa     Ocoa     Azua     Ocoa     Ocoa     Ocoa     Azua     Azua
108.6667  93.5000 108.6667 108.6667  93.5000 108.6667 108.6667 108.6667  93.5000  93.5000

 Otro ejemplo es que podemos colocar el ingreso relativo de cada individuo respecto a su familia:

 Library(dplyr)
 
my_datos <- my_datos %>%
  mutate(ing_rel = ingreso/tapply(ingreso, provincia, mean)[as.character(provincia)])
 
my_datos

1.3.   Tablas de contingencias

Usar una lista para agregar múltiples factores. Para ilustrarlo agregamos la variable edad. y agregamos una tabla especial donde se muestre la edad promedio por rango de edad, según provincia. Primero creamos una variable dummy cuyo 1 corresponde aquellos individuos menores de edad, usando la función mutate del paquete dplyr, posteriormente ilustramos varios ejemplos de tablas de contingencia.

my_datos <- my_datos %>%
            mutate(menor = factor(edad<=17, label = c("PET","Menor")))
 
  provincia ingreso edad   ing_rel menor
1       Ocoa      75   20 0.6901840   PET
2       Azua     115   20 1.2299465   PET
3       Ocoa     122   26 1.1226994   PET
4       Ocoa     117   25 1.0766871   PET
5       Azua      91   24 0.9732620   PET
6       Ocoa     145   26 1.3343558   PET
7       Ocoa     112   25 1.0306748   PET
8       Ocoa      81   20 0.7453988   PET
9       Azua      34    8 0.3636364 Menor
10      Azua     134   24 1.4331551   PET
 
tapply(my_datos$ingreso, my_datos$provincia, mean)
Azua     Ocoa
 93.5000 108.6667

O una lista de variables:

tapply(my_datos$ingreso, list(my_datos$provincia, my_datos$menor), mean)
         PET Menor
Azua 113.3333    34
Ocoa 108.6667    NA

Creando variables por grupos en dplyr (group_by + mutate)

  Simulemos una base de hogares, donde se identifica el hogar, el sexo (1 mujer) y provincia y edad para cada miembro.   # Definir la lista ...