Sesión 5 Transformacion y agrupacion de datos
En esta sección mostraremos herramientas de transformación y agrupación de datos (arreo de datos!). Trataremos los siguientes puntos:
Transformación de datos.
Estrategia separa-aplica-combina.
Es sorprendente que una gran variedad de necesidades de transformación de datos se pueden resolver con pocas funciones, en esta sección veremos 5 verbos que fueron diseñados para la tarea de transformación de datos y que comparten una filosofía en cuanto a su estructura. Estudiaremos las siguientes funciones:
- filter: obten un subconjunto de las filas de acuerdo a un criterio.
- select: selecciona columnas de acuerdo al nombre
- arrange: reordena las filas
- mutate: agrega nuevas variables
- summarise: reduce variables a valores (crear nuevas tablas con resúmenes de variables de la base original)
Estas funciones trabajan de manera similar, el primer argumento que reciben
es un data.frame
, los argumentos que siguen indican que operación se va a
efectuar y el resultado es un nuevo data.frame
.
Adicionalmente, se pueden usar con group_by()
que veremos más adelante y que
cambia el dominio de cada función, pasando de operar en el conjunto de datos
completos a operar en grupos.
Usaremos los datos de población municipal de INEGI que leímos en la sección anterior.
library(tidyverse)
<- read_csv("datos/df_municipios.csv")
df_mxmunicipio #> Rows: 2457 Columns: 8
#> ── Column specification ────────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (3): state_abbr, municipio_name, metro_area
#> dbl (5): pop, pop_male, pop_female, afromexican, indigenous
#>
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
<- read_csv("datos/df_edu.csv")
df_edu #> Rows: 7371 Columns: 12
#> ── Column specification ────────────────────────────────────────────────────────
#> Delimiter: ","
#> chr (3): state_abbr, municipio_name, sex
#> dbl (9): pop_15, no_school, preschool, elementary, secondary, highschool, hi...
#>
#> ℹ Use `spec()` to retrieve the full column specification for this data.
#> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Observemos la estructura de los datos:
<- as_tibble(df_mxmunicipio)
df_mxmunicipio glimpse(df_mxmunicipio)
#> Rows: 2,457
#> Columns: 8
#> $ state_abbr <chr> "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS",…
#> $ municipio_name <chr> "Aguascalientes", "Asientos", "Calvillo", "Cosío", "Jes…
#> $ pop <dbl> 877190, 46464, 56048, 15577, 120405, 46473, 53866, 8896…
#> $ pop_male <dbl> 425731, 22745, 27298, 7552, 60135, 22490, 26693, 4276, …
#> $ pop_female <dbl> 451459, 23719, 28750, 8025, 60270, 23983, 27173, 4620, …
#> $ afromexican <dbl> 532, 3, 10, 0, 32, 3, 13, 13, 4, 0, 43, 1139, 351, 186,…
#> $ indigenous <dbl> 104125, 1691, 7358, 2213, 8679, 6232, 6714, 1733, 3468,…
#> $ metro_area <chr> "Aguascalientes", NA, NA, NA, "Aguascalientes", NA, NA,…
glimpse(df_edu)
#> Rows: 7,371
#> Columns: 12
#> $ state_abbr <chr> "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS",…
#> $ municipio_name <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes", "…
#> $ sex <chr> "Total", "Hombres", "Mujeres", "Total", "Hombres", "Muj…
#> $ pop_15 <dbl> 631064, 301714, 329350, 31013, 14991, 16022, 38678, 184…
#> $ no_school <dbl> 2.662329, 2.355211, 2.943677, 4.011221, 4.389300, 3.657…
#> $ preschool <dbl> 0.17335801, 0.17466873, 0.17215728, 0.25795634, 0.29350…
#> $ elementary <dbl> 20.15247, 18.60073, 21.57401, 33.77938, 35.48129, 32.18…
#> $ secondary <dbl> 29.31145, 30.37976, 28.33278, 39.21259, 37.45581, 40.85…
#> $ highschool <dbl> 23.31824, 22.84912, 23.74799, 16.07068, 15.67607, 16.43…
#> $ higher_edu <dbl> 24.291989, 25.560299, 23.130105, 6.355399, 6.357148, 6.…
#> $ other <dbl> 0.09016518, 0.08020841, 0.09928647, 0.31277206, 0.34687…
#> $ schoolyrs <dbl> 10.211152, 10.380144, 10.056383, 7.854005, 7.692086, 8.…
Filtrar
Creamos una tabla de datos de juguete para mostrar el funcionamiento de cada instrucción:
<- tibble(sexo = c("mujer", "hombre", "mujer", "mujer", "hombre"),
df_ej estatura = c(1.65, 1.80, 1.70, 1.60, 1.67))
df_ej#> # A tibble: 5 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 mujer 1.65
#> 2 hombre 1.8
#> 3 mujer 1.7
#> 4 mujer 1.6
#> 5 hombre 1.67
El primer argumento de filter()
es el nombre del data frame
, los
subsecuentes son las expresiones que indican que filas filtrar.
filter(df_ej, sexo == "mujer")
#> # A tibble: 3 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 mujer 1.65
#> 2 mujer 1.7
#> 3 mujer 1.6
filter(df_ej, estatura > 1.65 & estatura < 1.75)
#> # A tibble: 2 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 mujer 1.7
#> 2 hombre 1.67
Algunos operadores importantes para filtrar son:
> 1
x >= 1
x < 1
x <= 1
x != 1
x == 1
x %in% c("a", "b") x
Crea un subconjunto de los datos df_mxmunicipio
que
contenga únicamente los municipios de la CDMX (state_abbr
es CDMX
)
Los municipios de Nuevo León con más de 200,000 habitantes.
Los municipios donde más de la mitad la población se autoidentifica como afromexicana o parte afromexicana.
Observación ==
y operadores booleanos
Debemos tener cuidado al usar ==
, ¿qué devuelven las siguientes expresiones?
sqrt(2) ^ 2 == 2
1/49 * 49 == 1
Los resultados de arriba se deben a que las computadoras usan aritmética de precisión finita:
print(1/49 * 49, digits = 22)
#> [1] 0.9999999999999998889777
Para estos casos es útil usar la función near()
near(sqrt(2) ^ 2, 2)
#> [1] TRUE
near(1 / 49 * 49, 1)
#> [1] TRUE
Los operadores booleanos también son convenientes para filtrar:
# Conjuntos
| b # a o b
a & b # a y b
a & !b # a y no-b
a xor(a, b)
El siguiente esquema nos ayuda a entender que hace cada operación, x
está
representada por el círculo del lado izquierdo y y
por el círculo del lado
derecho, la parte sombreada muestra las regiones que selecciona el operador:
Observación: faltantes NA
Un caso común es cuando se desea eliminar o localizar los registros con
faltantes en una o más columnas de las tablas de datos, en R los datos faltantes
se expresan como NA
, para seleccionar los registros con faltante en la
variable schoolyrs
de los datos df_edu
resulta natural escribir:
filter(df_edu, schoolyrs == NA)
#> # A tibble: 0 × 12
#> # … with 12 variables: state_abbr <chr>, municipio_name <chr>, sex <chr>,
#> # pop_15 <dbl>, no_school <dbl>, preschool <dbl>, elementary <dbl>,
#> # secondary <dbl>, highschool <dbl>, higher_edu <dbl>, other <dbl>,
#> # schoolyrs <dbl>
#> # ℹ Use `colnames()` to see all variable names
Y para eliminarlos
filter(df_edu, schoolyrs != NA)
#> # A tibble: 0 × 12
#> # … with 12 variables: state_abbr <chr>, municipio_name <chr>, sex <chr>,
#> # pop_15 <dbl>, no_school <dbl>, preschool <dbl>, elementary <dbl>,
#> # secondary <dbl>, highschool <dbl>, higher_edu <dbl>, other <dbl>,
#> # schoolyrs <dbl>
#> # ℹ Use `colnames()` to see all variable names
en ambos casos nos devuelve una tabla vacía!
El problema resulta de usar los operadores ==
y !=
, pensemos ¿qué regresan
las siguientes expresiones?
5 + NA
NA / 2
sum(c(5, 4, NA))
mean(c(5, 4, NA))
NA < 3
NA == 3
NA == NA
Las expresiones anteriores regresan NA
, el hecho que la media de un vector
que incluye NA
s o su suma regrese NA
s se debe a que por defecto en R se
propagan los valores faltantes, esto es, si deconozco el valor de una de las
componentes de un vector, también desconozco la suma del mismo; sin embargo,
muchas funciones tienen un argumento na.rm para eliminarlos,
sum(c(5, 4, NA), na.rm = TRUE)
#> [1] 9
mean(c(5, 4, NA), na.rm = TRUE)
#> [1] 4.5
Aún queda pendiente como filtrarlos en una tabla, para esto veamos que el manejo de datos faltantes en R utiliza una lógica ternaria (como SQL):
NA == NA
#> [1] NA
La expresión anterior puede resultar confusa, una manera de pensar en esto es considerar los NA como no sé, por ejemplo si no se la edad de Juan y no se la edad de Esteban, la respuesta a ¿Juan tiene la misma edad que Esteban? es no sé (NA).
<- NA
edad_Juan <- NA
edad_Esteban == edad_Esteban
edad_Juan #> [1] NA
<- 32
edad_Jose # Juan es menor que José?
< edad_Jose
edad_Juan #> [1] NA
Por tanto para determinar si un valor es faltante usamos la instrucción
is.na()
.
is.na(NA)
#> [1] TRUE
Y finalmente podemos filtrar,
filter(df_edu, is.na(schoolyrs))
Seleccionar
Elegir columnas de un conjunto de datos.
df_ej#> # A tibble: 5 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 mujer 1.65
#> 2 hombre 1.8
#> 3 mujer 1.7
#> 4 mujer 1.6
#> 5 hombre 1.67
select(df_ej, sexo)
#> # A tibble: 5 × 1
#> sexo
#> <chr>
#> 1 mujer
#> 2 hombre
#> 3 mujer
#> 4 mujer
#> 5 hombre
select(df_ej, -sexo)
#> # A tibble: 5 × 1
#> estatura
#> <dbl>
#> 1 1.65
#> 2 1.8
#> 3 1.7
#> 4 1.6
#> 5 1.67
select(df_ej, starts_with("s"))
select(df_ej, contains("x"))
Ve la ayuda de select (?select
) y escribe tres
maneras de seleccionar las variables del estado en los datos df_mxmunicipio
.
Ordenar
Ordenar de acuerdo al valor de una o más variables:
arrange(df_ej, sexo)
#> # A tibble: 5 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 hombre 1.8
#> 2 hombre 1.67
#> 3 mujer 1.65
#> 4 mujer 1.7
#> 5 mujer 1.6
arrange(df_ej, desc(estatura))
#> # A tibble: 5 × 2
#> sexo estatura
#> <chr> <dbl>
#> 1 hombre 1.8
#> 2 mujer 1.7
#> 3 hombre 1.67
#> 4 mujer 1.65
#> 5 mujer 1.6
Ordena los municipios por población, de mayor a menor.
¿Cuáles son los municipios con mayor disparidad de sexo (a total)?
¿Cuáles son los municipios con mayor disparidad de sexo (proporcional)?, elimina los municipios con menos de 5000 habitantes y repite.
Mutar
Mutar consiste en crear nuevas variables aplicando una función a columnas existentes:
mutate(df_ej, estatura_cm = estatura * 100)
#> # A tibble: 5 × 3
#> sexo estatura estatura_cm
#> <chr> <dbl> <dbl>
#> 1 mujer 1.65 165
#> 2 hombre 1.8 180
#> 3 mujer 1.7 170
#> 4 mujer 1.6 160
#> 5 hombre 1.67 167
mutate(df_ej, estatura_cm = estatura * 100, estatura_in = estatura_cm * 0.3937)
#> # A tibble: 5 × 4
#> sexo estatura estatura_cm estatura_in
#> <chr> <dbl> <dbl> <dbl>
#> 1 mujer 1.65 165 65.0
#> 2 hombre 1.8 180 70.9
#> 3 mujer 1.7 170 66.9
#> 4 mujer 1.6 160 63.0
#> 5 hombre 1.67 167 65.7
Calcula el porcentaje de población indígena de cada municipio y almacenalo en una nueva variable.
- Crea una nueva variable que muestre el cociente entre la población femenina y masculina.
Summarise y resúmenes por grupo
Summarise sirve para crear nuevas tablas con resúmenes o agregaciones de los datos originales.
summarise(df_ej, promedio = mean(estatura))
#> # A tibble: 1 × 1
#> promedio
#> <dbl>
#> 1 1.68
Calcula la población total, indígena y afromexicana a total.
La mayor utlidad de summarise
es cuando la combinamos con una variable de
agrupación y esta combinación es la estrategia separa-aplica combina.
Separa-aplica-combina (split-apply-combine)
Muchos problemas de análisis de datos involucran la aplicación de la estrategia separa-aplica-combina (Hadley Wickham 2011), esta consiste en romper un problema en pedazos (de acuerdo a una variable de interés), operar sobre cada subconjunto de manera independiente (ej. calcular la media de cada grupo, ordenar observaciones por grupo, estandarizar por grupo) y después unir los pedazos nuevamente. El siguiente diagrama ejemplifiaca el paradigma de divide-aplica-combina:
- Separa la base de datos original.
- Aplica funciones a cada subconjunto.
- Combina los resultados en una nueva base de datos.
Ahora, cuando pensamos como implementar la estrategia divide-aplica-combina es
natural pensar en iteraciones, por ejemplo utilizar un ciclo for
para recorrer cada grupo de interés y aplicar las funciones resumen, sin embargo la aplicación
de ciclos for
desemboca en código difícil de entender por lo que preferimos
trabajar con funciones creadas para estas tareas, usaremos el paquete
dplyr
que además de ser más claro suele ser más veloz.
Podemos hacer resúmenes por grupo, primero creamos una base de datos agrupada:
<- group_by(df_ej, sexo)
by_sexo
by_sexo#> # A tibble: 5 × 2
#> # Groups: sexo [2]
#> sexo estatura
#> <chr> <dbl>
#> 1 mujer 1.65
#> 2 hombre 1.8
#> 3 mujer 1.7
#> 4 mujer 1.6
#> 5 hombre 1.67
y después operamos sobre cada grupo, creando un resumen a nivel grupo y uniendo los subconjuntos en una base nueva:
summarise(by_sexo, promedio = mean(estatura))
#> # A tibble: 2 × 2
#> sexo promedio
#> <chr> <dbl>
#> 1 hombre 1.74
#> 2 mujer 1.65
Calcula la población total por estado.
Calcula la población indígena y afromexicana por estado.
¿Qué otros resúmenes puedes hacer para explorar los datos?
Algunas funciones útiles con summarise son min(x), median(x), max(x), quantile(x, p), n(), sum(x), sum(x > 1), mean(x > 1), sd(x).
Por ejemplo, para cada área metropolitana: cuántos municipios engloba (n()
),
la población total (sum()
) y al estado al que pertenece (first()
).
<- group_by(df_mxmunicipio, metro_area)
by_metro_area <- filter(by_metro_area, !is.na(metro_area))
no_miss <- summarise(no_miss, state = first(state_abbr),
pop_metro_area n_municipios = n(), pop_total = sum(pop))
head(pop_metro_area)
#> # A tibble: 6 × 4
#> metro_area state n_municipios pop_total
#> <chr> <chr> <int> <dbl>
#> 1 Acapulco GRO 2 886975
#> 2 Acayucan VER 3 120340
#> 3 Aguascalientes AGS 3 1044049
#> 4 Cancún QROO 2 763121
#> 5 Celaya GTO 3 635706
#> 6 Chihuahua CHIH 3 918339
Operador pipeline
En R, cuando uno hace varias operaciones es difícil leer y entender el código:
library(estcomp)
#>
#> Attaching package: 'estcomp'
#> The following object is masked _by_ '.GlobalEnv':
#>
#> df_edu
summarise(group_by(filter(election_2012, !is.na(section_type)), region,
n = n(), pri_pvem = sum(pri_pvem),
section_type), prd_pt_mc = sum(prd_pt_mc), pan = sum(pan))
#> `summarise()` has grouped output by 'region'. You can override using the
#> `.groups` argument.
#> # A tibble: 24 × 6
#> # Groups: region [8]
#> region section_type n pri_pvem prd_pt_mc pan
#> <chr> <chr> <int> <int> <int> <int>
#> 1 centronorte M 2071 331221 143225 228112
#> 2 centronorte R 5049 651507 211524 447886
#> 3 centronorte U 8940 1229241 653540 1171415
#> 4 centrosur M 1839 324327 277470 126264
#> 5 centrosur R 2541 495288 223978 181755
#> 6 centrosur U 27515 3698793 4765575 1936586
#> 7 este M 3158 462510 370352 306124
#> 8 este R 6768 905078 521793 654839
#> 9 este U 11403 1373876 1602217 1179497
#> 10 noreste M 1259 176191 77062 169285
#> # … with 14 more rows
#> # ℹ Use `print(n = ...)` to see more rows
La dificultad radica en que usualmente los parámetros se asignan después del nombre de la función usando ().
Una alternativa es ir almacenando las salidas en tablas de datos intermedias pero esto resulta poco práctico porque: 1) almacenamos en el mismo objeto sobreescribiendo ó 2) terminamos con muchos objetos con nombres poco significativos.
El operador Forward Pipe (|>
) cambia el orden en que se asignan los
parámetros, de manera que un parámetro que precede a la función es enviado
(“piped”) a la función:
x |> f(y)
se vuelvef(x, y)
,
x |> f(y) |> g(z)
se vuelveg(f(x, y), z)
.
Es así que podemos reescribir el código para poder leer las operaciones que vamos aplicando de izquierda a derecha y de arriba hacia abajo.
Veamos como cambia el código del ejemplo:
|>
election_2012 filter(!is.na(section_type)) |>
group_by(region, section_type) |>
summarise(
n = n(),
pri_pvem = sum(pri_pvem),
prd_pt_mc = sum(prd_pt_mc),
pan = sum(pan)
) #> `summarise()` has grouped output by 'region'. You can override using the
#> `.groups` argument.
#> # A tibble: 24 × 6
#> # Groups: region [8]
#> region section_type n pri_pvem prd_pt_mc pan
#> <chr> <chr> <int> <int> <int> <int>
#> 1 centronorte M 2071 331221 143225 228112
#> 2 centronorte R 5049 651507 211524 447886
#> 3 centronorte U 8940 1229241 653540 1171415
#> 4 centrosur M 1839 324327 277470 126264
#> 5 centrosur R 2541 495288 223978 181755
#> 6 centrosur U 27515 3698793 4765575 1936586
#> 7 este M 3158 462510 370352 306124
#> 8 este R 6768 905078 521793 654839
#> 9 este U 11403 1373876 1602217 1179497
#> 10 noreste M 1259 176191 77062 169285
#> # … with 14 more rows
#> # ℹ Use `print(n = ...)` to see more rows
podemos leer |> como “después”.
Tip: Un atajo para producir el operador pipeline |>
es
shift + ctrl/cmd + M
Siguiendo con los datos election_2012
, ¿Qué estados
tienen la mayor participación (esto es del total de votantes en la lista nominal
que porcentaje asistió a votar)? Tip: debes eliminar las casillas especiales pues la lista nominal (ln
) no está definida.
Variables por grupo (ventanas)
En ocasiones es conveniente crear variables por grupo, por ejemplo estandarizar
dentro de cada grupo z = (x - mean(x)) / sd(x). Para esto usamos group_by()
y mutate()
.
Veamos un ejemplo:
<- election_2012 |>
z_prd_pt_mc_state filter(total > 50, !is.na(section_type)) |>
mutate(prd_pt_mc_pct = prd_pt_mc / total) |>
group_by(state_abbr) |>
mutate(
n = n(),
sd_prd_pt_mc = sd(prd_pt_mc_pct),
mean_prd_pt_mc = mean(prd_pt_mc_pct),
z_prd_pt_mc = (prd_pt_mc_pct - mean_prd_pt_mc) / sd_prd_pt_mc
)
Verbos de dos tablas
Muchas veces debemos reunir información que está almacenada a lo largo de
muchas tablas, por ejemplo, si nos interesa conocer como se relaciona el año de
escolaridad promedio (schoolyrs
en el df_edu
) con el porcentaje de
población indígena (indigenous
en df_mxmunicipios
), debemos poder pegar
las dos tablas.
Hay varias maneras de unir dos tablas, por ejemplo:
<- tibble(name = c("John", "Paul", "George", "Ringo", "Stuart", "Pete"),
x instrument = c("guitar", "bass", "guitar", "drums", "bass",
"drums"))
<- tibble(name = c("John", "Paul", "George", "Ringo", "Brian"),
y band = c("TRUE", "TRUE", "TRUE", "TRUE", "FALSE"))
x#> # A tibble: 6 × 2
#> name instrument
#> <chr> <chr>
#> 1 John guitar
#> 2 Paul bass
#> 3 George guitar
#> 4 Ringo drums
#> 5 Stuart bass
#> 6 Pete drums
y#> # A tibble: 5 × 2
#> name band
#> <chr> <chr>
#> 1 John TRUE
#> 2 Paul TRUE
#> 3 George TRUE
#> 4 Ringo TRUE
#> 5 Brian FALSE
inner_join(x, y)
#> Joining, by = "name"
#> # A tibble: 4 × 3
#> name instrument band
#> <chr> <chr> <chr>
#> 1 John guitar TRUE
#> 2 Paul bass TRUE
#> 3 George guitar TRUE
#> 4 Ringo drums TRUE
left_join(x, y)
#> Joining, by = "name"
#> # A tibble: 6 × 3
#> name instrument band
#> <chr> <chr> <chr>
#> 1 John guitar TRUE
#> 2 Paul bass TRUE
#> 3 George guitar TRUE
#> 4 Ringo drums TRUE
#> 5 Stuart bass <NA>
#> 6 Pete drums <NA>
semi_join(x, y)
#> Joining, by = "name"
#> # A tibble: 4 × 2
#> name instrument
#> <chr> <chr>
#> 1 John guitar
#> 2 Paul bass
#> 3 George guitar
#> 4 Ringo drums
anti_join(x, y)
#> Joining, by = "name"
#> # A tibble: 2 × 2
#> name instrument
#> <chr> <chr>
#> 1 Stuart bass
#> 2 Pete drums
Resumamos lo que observamos arriba:
Tipo | Acción |
---|---|
inner | Incluye únicamente las filas que aparecen tanto en x como en y |
left | Incluye todas las filas en x y las filas de y que coincidan |
semi | Incluye las filas de x que coincidan con y |
anti | Incluye las filas de x que no coinciden con y |
Ahora tu turno, ¿cómo se relacionan los años de
escolaridad con el porcentaje de población indígena. Utiliza los datos
df_mxmunicipio
y df_edu
para explorar la relación. ¿cuál es el join
adecuado? ¿de qué tamaño serán los datos finales?
glimpse(df_edu)
#> Rows: 7,371
#> Columns: 12
#> $ state_abbr <chr> "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS",…
#> $ municipio_name <chr> "Aguascalientes", "Aguascalientes", "Aguascalientes", "…
#> $ sex <chr> "Total", "Hombres", "Mujeres", "Total", "Hombres", "Muj…
#> $ pop_15 <dbl> 631064, 301714, 329350, 31013, 14991, 16022, 38678, 184…
#> $ no_school <dbl> 2.662329, 2.355211, 2.943677, 4.011221, 4.389300, 3.657…
#> $ preschool <dbl> 0.17335801, 0.17466873, 0.17215728, 0.25795634, 0.29350…
#> $ elementary <dbl> 20.15247, 18.60073, 21.57401, 33.77938, 35.48129, 32.18…
#> $ secondary <dbl> 29.31145, 30.37976, 28.33278, 39.21259, 37.45581, 40.85…
#> $ highschool <dbl> 23.31824, 22.84912, 23.74799, 16.07068, 15.67607, 16.43…
#> $ higher_edu <dbl> 24.291989, 25.560299, 23.130105, 6.355399, 6.357148, 6.…
#> $ other <dbl> 0.09016518, 0.08020841, 0.09928647, 0.31277206, 0.34687…
#> $ schoolyrs <dbl> 10.211152, 10.380144, 10.056383, 7.854005, 7.692086, 8.…
glimpse(df_mxmunicipio)
#> Rows: 2,457
#> Columns: 8
#> $ state_abbr <chr> "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS", "AGS",…
#> $ municipio_name <chr> "Aguascalientes", "Asientos", "Calvillo", "Cosío", "Jes…
#> $ pop <dbl> 877190, 46464, 56048, 15577, 120405, 46473, 53866, 8896…
#> $ pop_male <dbl> 425731, 22745, 27298, 7552, 60135, 22490, 26693, 4276, …
#> $ pop_female <dbl> 451459, 23719, 28750, 8025, 60270, 23983, 27173, 4620, …
#> $ afromexican <dbl> 532, 3, 10, 0, 32, 3, 13, 13, 4, 0, 43, 1139, 351, 186,…
#> $ indigenous <dbl> 104125, 1691, 7358, 2213, 8679, 6232, 6714, 1733, 3468,…
#> $ metro_area <chr> "Aguascalientes", NA, NA, NA, "Aguascalientes", NA, NA,…
Si queremos un mapa del ganador de las elecciones por estado debemos unir los
datos de elecciones con datos geográficos, estos estan incluídos en mxmaps
,
son mxstate.map
.
data(election_sub_2012)
<- election_2012 |>
election_2012_state group_by(state_code) |>
summarise(
pri_pvem = 100 * sum(pri_pvem) / sum(total),
pan = 100 * sum(pan) / sum(total),
prd_pt_mc = 100 * sum(prd_pt_mc) / sum(total)
|>
) mutate(winner = case_when(
> pan & pri_pvem > prd_pt_mc ~ "pri_pvem",
pri_pvem > pri_pvem & pan > prd_pt_mc ~ "pan",
pan TRUE ~ "prd_pt_mc"),
winner_pct = pmax(pri_pvem, pan, prd_pt_mc))
<- mxstate.map |>
election_map left_join(election_2012_state, by = c("region" = "state_code"))
ggplot(election_map, aes(long, lat, group = group)) +
geom_polygon(aes(fill = winner)) +
coord_map()
Podemos especificar el color de cada categoría y la intensidad puede variar de acuerdo al porcentaje de votos que se llevó el partido/alianza ganador.
library(patchwork)
<- ggplot(election_map, aes(long, lat, group = group)) +
map_edo geom_polygon(aes(fill = winner, alpha = winner_pct), color = "#666666",
size = .05, show.legend = FALSE) +
coord_map() +
scale_fill_manual(values = c("prd_pt_mc" = "#FFCC00", "pan" = "#3399FF",
"pri_pvem" = "#00CD66")) +
theme_void()
<- mxhexbin.map |>
election_hexbinmap left_join(election_2012_state, by = c("region" = "state_code"))
<- mxhexbin.map |>
state_labels_map group_by(state_abbr) |>
summarise(long = mean(long), lat = mean(lat), group = first(group))
<- ggplot(election_hexbinmap, aes(long, lat,
hexbinmap_edo group = group)) +
geom_polygon(aes(fill = winner, alpha = winner_pct), color = "#666666",
size = .05, show.legend = FALSE) +
coord_map() +
scale_fill_manual(values = c("prd_pt_mc" = "#FFCC00", "pan" = "#3399FF",
"pri_pvem" = "#00CD66")) +
geom_text(data = state_labels_map, aes(long, lat, label = state_abbr)) +
theme_void()
# con patchwork podemos hacer:
+ hexbinmap_edo map_edo
Genera un mapa a nivel estado que muestre el porcentaje de la población casada a total (mayores de 12 años).