Instalar paquetes de tidyverse y cargar tidyverse y readxl
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library (readxl)
knitr:: opts_chunk$ set (echo = TRUE )
Tidyverse
Conjunto de paquetes con sintáxis similar para facilitar el uso conjunto de funciones.
Ventajas:
Permiten encadenar una serie de procesos sin necesidad de ir guardando productos intermedios en objetos basura.
Código más fácil de leer.
Bastante amigable para principiantes.
Muchas funciones permiten hacer lo mismo que R base.
Casi todas las operaciones se realizan de manera vectorizada (evita usar tiempo de cómputo en ciclos no necesarios).
Sin embargo, no a todo mundo le gusta porque dice que cambia mucho la sintáxis de R base.
En inglés conocido como data wrangling.
datos <- read_excel ("INFyS_2015_2020_Michoacan_de_Ocampo_lHwLKIM.xlsx" ,
sheet = "Arbolado" )
Warning: Expecting numeric in BW19313 / R19313C75: got 'NULL'
Warning: Expecting numeric in BX19313 / R19313C76: got 'NULL'
#Mostrar la parte superior de los datos
head (datos)
# A tibble: 6 × 76
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3 CVEECON1_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr> <dbl>
1 40277 67761 801985 2019 16 Michoacá… 14
2 40277 67761 802033 2019 16 Michoacá… 14
3 40277 67761 802948 2019 16 Michoacá… 14
4 40279 67762 135014 2015 16 Michoacá… 14
5 40279 67762 135029 2015 16 Michoacá… 14
6 40279 67762 135035 2015 16 Michoacá… 14
# ℹ 69 more variables: CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>,
# DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>,
# NoRama_C3 <dbl>, Azimut_C3 <dbl>, Distancia_C3 <dbl>, NombreComun_C3 <chr>,
# Familia_APG_C3 <chr>, Genero_APG_C3 <chr>, Especie_APG_C3 <chr>, …
#Mostrar su estructura
str (datos)
tibble [26,035 × 76] (S3: tbl_df/tbl/data.frame)
$ UPMID : num [1:26035] 40277 40277 40277 40279 40279 ...
$ IdConglomerado : num [1:26035] 67761 67761 67761 67762 67762 ...
$ ArboladoID_C3 : num [1:26035] 801985 802033 802948 135014 135029 ...
$ Anio_C3 : num [1:26035] 2019 2019 2019 2015 2015 ...
$ Cve_Estado_C3 : num [1:26035] 16 16 16 16 16 16 16 16 16 16 ...
$ Estado_C3 : chr [1:26035] "Michoacán de Ocampo" "Michoacán de Ocampo" "Michoacán de Ocampo" "Michoacán de Ocampo" ...
$ CVEECON1_C3 : num [1:26035] 14 14 14 14 14 14 14 14 14 14 ...
$ CVEECON2_C3 : num [1:26035] 14.5 14.5 14.5 14.5 14.5 14.5 14.5 14.5 14.5 14.5 ...
$ CVEECON3_C3 : chr [1:26035] "14.5.2" "14.5.2" "14.5.2" "14.5.2" ...
$ CVEECON4_C3 : chr [1:26035] "14.5.2.3" "14.5.2.3" "14.5.2.3" "14.5.2.3" ...
$ DESECON1_C3 : chr [1:26035] "Selvas Calido-Secas" "Selvas Calido-Secas" "Selvas Calido-Secas" "Selvas Calido-Secas" ...
$ DESECON2_C3 : chr [1:26035] "Planicie Costera y Lomerios del Pacifico Sur" "Planicie Costera y Lomerios del Pacifico Sur" "Planicie Costera y Lomerios del Pacifico Sur" "Planicie Costera y Lomerios del Pacifico Sur" ...
$ DESECON3_C3 : chr [1:26035] "Lomerios y Piedemontes del Pacifico Sur Mexicano con Selva Espinosa" "Lomerios y Piedemontes del Pacifico Sur Mexicano con Selva Espinosa" "Lomerios y Piedemontes del Pacifico Sur Mexicano con Selva Espinosa" "Lomerios y Piedemontes del Pacifico Sur Mexicano con Selva Espinosa" ...
$ DESECON4_C3 : chr [1:26035] "Planicie Costera y lomerios del Pacifico Sur con selva baja caducifolia" "Planicie Costera y lomerios del Pacifico Sur con selva baja caducifolia" "Planicie Costera y lomerios del Pacifico Sur con selva baja caducifolia" "Planicie Costera y lomerios del Pacifico Sur con selva baja caducifolia" ...
$ Region_Hidrologica_C3 : chr [1:26035] "Costa de Michoacan" "Costa de Michoacan" "Costa de Michoacan" "Costa de Michoacan" ...
$ CVE_S7_C3 : chr [1:26035] "BPQ" "BPQ" "BPQ" "VSA/BPQ" ...
$ X_C3 : num [1:26035] -103 -103 -103 -102 -102 ...
$ Y_C3 : num [1:26035] 18.2 18.2 18.2 18.2 18.2 ...
$ DESCRIP_S7_C3 : chr [1:26035] "BOSQUE DE PINO-ENCINO" "BOSQUE DE PINO-ENCINO" "BOSQUE DE PINO-ENCINO" "VEGETACIÓN SECUNDARIA ARBÓREA DE BOSQUE DE PINO-ENCINO" ...
$ FORM_S7_C3 : chr [1:26035] "Coníferas y latifoliadas" "Coníferas y latifoliadas" "Coníferas y latifoliadas" "Coníferas y latifoliadas" ...
$ FAO_S7_C3 : logi [1:26035] NA NA NA NA NA NA ...
$ ECO_S7_C3 : chr [1:26035] "Bosques" "Bosques" "Bosques" "Bosques" ...
$ Sitio_C3 : num [1:26035] 1 3 4 1 1 1 1 2 2 3 ...
$ Consecutivo_C3 : num [1:26035] 9 19 13 1 14 20 22 12 8 2 ...
$ NoIndividuo_C3 : num [1:26035] 9 10 8 1 14 20 22 12 8 2 ...
$ NoRama_C3 : num [1:26035] 9 19 13 1 16 22 24 12 8 2 ...
$ Azimut_C3 : num [1:26035] 44 276 202 16 178 239 281 223 116 135 ...
$ Distancia_C3 : num [1:26035] 9.5 8.5 1 9.5 4.4 5.7 8.2 8.5 11.2 3.8 ...
$ NombreComun_C3 : chr [1:26035] "temezquite" "tocon" "ambula" "encino" ...
$ Familia_APG_C3 : chr [1:26035] "Fabaceae" "ZZ Familia Desconocida" "Hernandiaceae" "Pinaceae" ...
$ Genero_APG_C3 : chr [1:26035] "Lysiloma" "ZZ Genero Desconocido" "Gyrocarpus" "Pinus" ...
$ Especie_APG_C3 : chr [1:26035] "divaricatum" "NULL" "jatrophifolius" "oocarpa" ...
$ Categoria_APG_C3 : chr [1:26035] "NULL" "NULL" "NULL" "NULL" ...
$ Infraespecie_APG_C3 : chr [1:26035] "NULL" "NULL" "NULL" "NULL" ...
$ NombreCientifico_APG_C3 : chr [1:26035] "Lysiloma divaricatum" "ZZ Genero Desconocido" "Gyrocarpus jatrophifolius" "Pinus oocarpa" ...
$ Forma_Biologica_Cat_C3 : chr [1:26035] "Arbol" "Indeterminada" "Arbol" "Arbol" ...
$ FormaFuste_C3 : chr [1:26035] "Individuo curvo con dos o más fustes" "No capturado" "Individuo curvo con dos o más fustes" "individuo recto con un fuste" ...
$ Condicion_C3 : chr [1:26035] "Arbol vivo" "Tocon sin marca" "Arbol vivo" "Arbol vivo" ...
$ MuertoPie_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ GradoPutrefaccion_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ TipoTocon_C3 : chr [1:26035] "No capturado" "Tocón madera seca (madera dura sin evidencias de descomposición)" "No capturado" "No capturado" ...
$ DiametroNormal_C3 : num [1:26035] 7.9 41.2 11.2 16.4 8.7 17.8 25.4 17.4 27.5 36.4 ...
$ AlturaTotal_C3 : num [1:26035] 8.5 0.97 4.65 8.8 4.5 10.2 13.8 11 15 8.7 ...
$ AnguloInclinacion_C3 : num [1:26035] 999993 999993 999993 -1 -1 ...
$ AlturaFusteLimpio_C3 : num [1:26035] 4.3 1.0e+06 1.4 6.7 2.4 ...
$ AlturaComercial_C3 : num [1:26035] 1.0e+06 1.0e+06 1.4 5.0 1.0e+06 ...
$ DiametroCopaNS_C3 : num [1:26035] 4.2 1.0e+06 3.2 2.8 3.0 ...
$ DiametroCopaEO_C3 : num [1:26035] 3.4 1.0e+06 2.9 2.6 2.7 ...
$ DiametroCopa_C3 : num [1:26035] 3.80 1.00e+06 3.05 2.70 2.85 ...
$ ProporcionCopaViva_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ ExposicionCopa_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "SI" ...
$ PosicionCopa_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "Suprimido" ...
$ DensidadCopa_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ MuerteRegresiva_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ TransparenciaFollaje_C3 : chr [1:26035] "No capturado" "No capturado" "No capturado" "No capturado" ...
$ VigorEtapa_C3 : chr [1:26035] "Árbol joven" "No capturado" "Árbol joven" "Árbol joven" ...
$ NivelVigor_C3 : chr [1:26035] "Moderado" "No capturado" "Moderado" "No aplica" ...
$ AreaBasal_C3 : num [1:26035] 0.0049 0.13332 0.00985 0.02112 0.00594 ...
$ AreaCopa_C3 : num [1:26035] 1.13e+01 1.00e+06 7.30 5.73 6.38 ...
$ AgenteDanio1_C3 : chr [1:26035] "Ausencia de daño" "Actividades humanas" "Ausencia de daño" "Ausencia de daño" ...
$ AgenteDanio1_EST_C3 : chr [1:26035] "Ausencia de daño" "Actividades humanas" "Ausencia de daño" "Ausencia de daño" ...
$ Severidad1_C3 : chr [1:26035] "No aplica" "No aplica" "No aplica" "No aplica" ...
$ AgenteDanio2_C3 : chr [1:26035] "Ausencia de daño" "Actividades humanas" "Ausencia de daño" "No capturado" ...
$ AgenteDanio2_EST_C3 : chr [1:26035] "Ausencia de daño" "Actividades humanas" "Ausencia de daño" "No capturado" ...
$ Severidad2_C3 : chr [1:26035] "No aplica" "No aplica" "No aplica" "No aplica" ...
$ EsSubmuestra_C3 : num [1:26035] 0 0 0 0 0 0 0 0 0 0 ...
$ DiametroBasalSub_validacion_C3: num [1:26035] 1e+06 1e+06 1e+06 1e+06 1e+06 ...
$ Edad_C3 : num [1:26035] 1e+06 1e+06 1e+06 1e+06 1e+06 ...
$ NumeroAnillos25_C3 : num [1:26035] 1e+06 1e+06 1e+06 1e+06 1e+06 ...
$ LongitudAnillos10_C3 : num [1:26035] 1e+06 1e+06 1e+06 1e+06 1e+06 ...
$ GrosorCorteza_C3 : num [1:26035] 1e+06 1e+06 1e+06 1e+06 1e+06 ...
$ es_para_estimacion_Volumen_C3 : num [1:26035] 1 0 1 1 1 1 1 1 1 1 ...
$ VolumenVRTA_m3_C3 : num [1:26035] 2.64e-02 1.00e+06 2.75e-02 1.26e-01 1.24e-02 ...
$ es_para_estimacion_ByC : num [1:26035] 1 1 1 1 1 1 1 1 1 1 ...
$ biomasa_kg_C3 : num [1:26035] 21 35.3 10.5 72.1 18.2 ...
$ carbono_kg_C3 : num [1:26035] 9.22 15.76 4.7 35.29 8.05 ...
Tres paquetes esenciales para el data wrangling o acomodo de datos: tibble, dplyr y tidyr.
Tibble: paquete con un nuevo tipo de objeto similar a data.frame, pero con ciertas mejoras. Los tibbles son la base de trabajo del tidyverse.
Dplyr: Es un paquete que permite modificar y agregar variables, y hacer resumenes.
Tidyr: Es un paquete que permite acomodar datos y eliminar/rellenar datos faltantes.
El pipe
La base del tidyverse. Primero inventado en el paquete “magrittr” (%>%
). A partir de R 4.0 ya tiene una implementación base (|>
).
El pipe es equivalente a decir que lo que va antes del pipe es el primer argumento de la función.
Tibble
Es como un data.frame pero hace menos cosas:
No cambia el tipo de las entradas (p.ej., caracter a factor).
No cambia el nombre de las variables.
Nunca crea nombres de filas.
Además, tiene una versión mejorada de print para facilitar revisar los datos.
datos2 <- datos |>
as_tibble ()
datos2
# A tibble: 26,035 × 76
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 40277 67761 801985 2019 16 Michoacán de Ocampo
2 40277 67761 802033 2019 16 Michoacán de Ocampo
3 40277 67761 802948 2019 16 Michoacán de Ocampo
4 40279 67762 135014 2015 16 Michoacán de Ocampo
5 40279 67762 135029 2015 16 Michoacán de Ocampo
6 40279 67762 135035 2015 16 Michoacán de Ocampo
7 40279 67762 135037 2015 16 Michoacán de Ocampo
8 40279 67762 135060 2015 16 Michoacán de Ocampo
9 40279 67762 135056 2015 16 Michoacán de Ocampo
10 40279 67762 135069 2015 16 Michoacán de Ocampo
# ℹ 26,025 more rows
# ℹ 70 more variables: CVEECON1_C3 <dbl>, CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>,
# CVEECON4_C3 <chr>, DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>,
# DESECON4_C3 <chr>, Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>,
# X_C3 <dbl>, Y_C3 <dbl>, DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>,
# FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>, Sitio_C3 <dbl>, Consecutivo_C3 <dbl>,
# NoIndividuo_C3 <dbl>, NoRama_C3 <dbl>, Azimut_C3 <dbl>, …
[1] "tbl_df" "tbl" "data.frame"
Aquí vemos que la clase de los datos es tibble (abreviado como tibble: tbl
y tibble_dataframe: tbl_df
).
[1] "tbl_df" "tbl" "data.frame"
Si quieres nombrar columnas con caracteres especiales (p.ej., espacios, acentos, comenzar con números) se puede poner el nombre entre ` ` (backticks).
Hay dos formas básicas de crear tibbles a partir de datos.
tibble. Como data.frame, i.e., vector por atributo.
tribble. tibble transpuesto, i.e., vectores por filas.
tibble (a = 1 : 5 ,
b = letters[1 : 5 ])
# A tibble: 5 × 2
a b
<int> <chr>
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
tribble (~ a, ~ b,
1 ,"a" ,
2 , "b" ,
3 , "c" ,
4 , "d" ,
5 , "e" )
# A tibble: 5 × 2
a b
<dbl> <chr>
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
Dplyr
Notar que los nombres de las variables se escriben sin comillas. Si tienen caracteres especiales, con ` `.
Ver algunas características de nuestros datos.
Ver niveles de Tipos de vegetación. Recuerden que CVE_S7_C3 contiene la clave de tipos de vegetación.
Seleccionar columnas
Seleccionar ciertos atributos.
datos |>
distinct (CVE_S7_C3)
# A tibble: 32 × 1
CVE_S7_C3
<chr>
1 BPQ
2 VSA/BPQ
3 BQ
4 VSa/SBC
5 VSA/SMS
6 SBC
7 VM
8 VSa/BQ
9 PC
10 VSa/BPQ
# ℹ 22 more rows
datos |>
select (UPMID, CVE_S7_C3)
# A tibble: 26,035 × 2
UPMID CVE_S7_C3
<dbl> <chr>
1 40277 BPQ
2 40277 BPQ
3 40277 BPQ
4 40279 VSA/BPQ
5 40279 VSA/BPQ
6 40279 VSA/BPQ
7 40279 VSA/BPQ
8 40279 VSA/BPQ
9 40279 VSA/BPQ
10 40279 VSA/BPQ
# ℹ 26,025 more rows
Select es similar a seleccionar por número de columnas, pero haciendo referencia al nombre de la columna. Los nombres de las columnas se ponen sin concatenarlos en un vector (es decir, sin c
).
Obtener valores distintos o únicos
Principal diferencia de distinct
con unique
es que retorna un tibble, en lugar de vector. Si se quiere obtener un vector se puede usar pull
.
datos |>
distinct (CVE_S7_C3) |>
pull (CVE_S7_C3)
[1] "BPQ" "VSA/BPQ" "BQ" "VSa/SBC" "VSA/SMS" "SBC" "VM"
[8] "VSa/BQ" "PC" "VSa/BPQ" "VSa/BP" "BP" "VSA/SBC" "VSA/BQ"
[15] "VSA/BP" "BQP" "VSa/BQP" "TAP" "RAP" "TA" "AH"
[22] "BA" "BC" "VSa/BA" "BM" "VSA/BA" "VSA/BM" "PI"
[29] "RP" "VSA/BQP" "RA" "TP"
Ver número de valores por columna.
datos |>
select (CVE_S7_C3) |>
n_distinct ()
Agregar nuevas columnas
Agregar nuevas columnas se hace con mutate
. Primero se pone el nuevo nombre de la columna y luego a lo que equivale.
datos |>
select (DiametroNormal_C3) |>
mutate (DiametroNormal_C3_m = DiametroNormal_C3/ 100 )
# A tibble: 26,035 × 2
DiametroNormal_C3 DiametroNormal_C3_m
<dbl> <dbl>
1 7.9 0.079
2 41.2 0.412
3 11.2 0.112
4 16.4 0.164
5 8.7 0.087
6 17.8 0.178
7 25.4 0.254
8 17.4 0.174
9 27.5 0.275
10 36.4 0.364
# ℹ 26,025 more rows
Renombrar columnas.
Renombrar se hace con rename
. Primero se pone nuevo nombre y luego el viejo.
datos |>
select (DiametroNormal_C3) |>
rename ("DAP" = "DiametroNormal_C3" )
# A tibble: 26,035 × 1
DAP
<dbl>
1 7.9
2 41.2
3 11.2
4 16.4
5 8.7
6 17.8
7 25.4
8 17.4
9 27.5
10 36.4
# ℹ 26,025 more rows
Ordenar datos
Se usa arrange
. Por default los ordena de menor a mayor (ascendente). Si no se quiere esto, se usa desc
para ponerlos en orden descendente.
datos |>
select (DiametroNormal_C3) |>
arrange (DiametroNormal_C3)
# A tibble: 26,035 × 1
DiametroNormal_C3
<dbl>
1 7.6
2 7.6
3 7.6
4 7.6
5 7.6
6 7.6
7 7.6
8 7.6
9 7.6
10 7.6
# ℹ 26,025 more rows
datos |>
select (DiametroNormal_C3) |>
arrange (desc (DiametroNormal_C3))
# A tibble: 26,035 × 1
DiametroNormal_C3
<dbl>
1 999993
2 999993
3 999993
4 999993
5 999993
6 999993
7 999993
8 999993
9 999993
10 999993
# ℹ 26,025 more rows
Filtrar
Quedarse con una parte de los datos en función de algún criterio en particular.
datos |>
select (DiametroNormal_C3) |>
filter (DiametroNormal_C3 >= 99999 )
# A tibble: 625 × 1
DiametroNormal_C3
<dbl>
1 999993
2 999993
3 999993
4 999993
5 999993
6 999993
7 999993
8 999993
9 999993
10 999993
# ℹ 615 more rows
Si queremos más de una condición (i.e., y) se usa &
, operador ó es |
.
datos |>
select (DiametroNormal_C3) |>
filter (DiametroNormal_C3 <= 99999 & DiametroNormal_C3 >= 20 )
# A tibble: 6,488 × 1
DiametroNormal_C3
<dbl>
1 41.2
2 25.4
3 27.5
4 36.4
5 28.9
6 39.8
7 25.8
8 20
9 30.4
10 32.3
# ℹ 6,478 more rows
datos |>
select (DiametroNormal_C3) |>
filter (DiametroNormal_C3 <= 5 | DiametroNormal_C3 >= 20 )
# A tibble: 7,113 × 1
DiametroNormal_C3
<dbl>
1 41.2
2 25.4
3 27.5
4 36.4
5 28.9
6 39.8
7 25.8
8 20
9 30.4
10 32.3
# ℹ 7,103 more rows
Sobreescribir valores o modificar un columna en su lugar
Esto se hace con mutate(across())
.
Quitar valores de 99999 como NA
datos |>
filter (DiametroNormal_C3 >= 99999 )
# A tibble: 625 × 76
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 48449 65760 197636 2015 16 Michoacán de Ocampo
2 40287 67766 802997 2019 16 Michoacán de Ocampo
3 40289 67767 134939 2015 16 Michoacán de Ocampo
4 44863 66591 405491 2016 16 Michoacán de Ocampo
5 46036 66301 406677 2016 16 Michoacán de Ocampo
6 46132 66349 128928 2015 16 Michoacán de Ocampo
7 41362 67481 141665 2015 16 Michoacán de Ocampo
8 40287 67766 802966 2019 16 Michoacán de Ocampo
9 40287 67766 802967 2019 16 Michoacán de Ocampo
10 38204 68270 143190 2015 16 Michoacán de Ocampo
# ℹ 615 more rows
# ℹ 70 more variables: CVEECON1_C3 <dbl>, CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>,
# CVEECON4_C3 <chr>, DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>,
# DESECON4_C3 <chr>, Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>,
# X_C3 <dbl>, Y_C3 <dbl>, DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>,
# FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>, Sitio_C3 <dbl>, Consecutivo_C3 <dbl>,
# NoIndividuo_C3 <dbl>, NoRama_C3 <dbl>, Azimut_C3 <dbl>, …
datos2 <- datos |>
mutate (across (DiametroNormal_C3, ~ ifelse (.x >= 99999 , NA , .x)))
Across usa la sintáxis de ~
para determinar una función que le aplicas a lo que le pases, referenciado como .x
. El usar la notación ~(.x)
es similar a usar function(x)
con procesos más simples.
datos2 |>
filter (DiametroNormal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
datos2 <- datos |>
mutate (across (DiametroNormal_C3, function (x) {
resul <- ifelse (x >= 99999 , NA , x)
return (resul)
}))
datos2 |>
filter (DiametroNormal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
Lo mismo en R base
datos2 <- datos
datos2$ DiametroNormal_C3[datos2$ DiametroNormal_C3 >= 99999 ] <- NA
datos2 |>
filter (DiametroNormal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
Hacer lo mismo para Altura.
datos2 <- datos |>
mutate (across (AlturaTotal_C3, ~ ifelse (.x >= 99999 , NA , .x)))
datos2 |>
filter (AlturaTotal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
Varias transformaciones a la vez.
datos2 <- datos |>
mutate (across (c (AlturaTotal_C3, DiametroNormal_C3), ~ ifelse (.x >= 99999 , NA , .x)))
datos2 |>
filter (AlturaTotal_C3 >= 99999 | DiametroNormal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
Seleccionar varios tipos de variables por tipo o por nombre para modificarlas en su lugar. Eso se puede hacer con mutate(across())
y la ayuda de algunas de las siguientes funciones.
starts_with
ends_with
everything
where + is.numeric | is.character
datos2 <- datos |>
mutate (across (starts_with ("Diametro" ), ~ ifelse (.x >= 99999 , NA , .x)))
datos2 |>
filter (DiametroNormal_C3 >= 99999 | DiametroCopaNS_C3 >= 99999 | DiametroCopaEO_C3 >= 99999 | DiametroCopa_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
datos2 <- datos |>
mutate (across (where (is.numeric), ~ ifelse (.x >= 99999 , NA , .x)))
datos2 |>
select (UPMID, DiametroNormal_C3, AlturaTotal_C3) |>
mutate (across (everything (), ~ ifelse (.x >= 99999 , NA , .x)))
# A tibble: 26,035 × 3
UPMID DiametroNormal_C3 AlturaTotal_C3
<dbl> <dbl> <dbl>
1 40277 7.9 8.5
2 40277 41.2 0.97
3 40277 11.2 4.65
4 40279 16.4 8.8
5 40279 8.7 4.5
6 40279 17.8 10.2
7 40279 25.4 13.8
8 40279 17.4 11
9 40279 27.5 15
10 40279 36.4 8.7
# ℹ 26,025 more rows
Selección de columnas con vectores.
Este caso se usa cuando los nombres de las columnas no los sabes de antemano, pero los quieres pasar como un vector. En este caso se usa all_of
. Noten que cuando se usa all_of
, los nombres de las variables van entre comillas (como caracter). En cambio, si se ponen directamente en across, van sin comillas.
datos2 <- datos |>
mutate (across (all_of (c ("AlturaTotal_C3" , "DiametroNormal_C3" )), ~ ifelse (.x >= 99999 , NA , .x)))
datos2 <- datos |>
mutate (across (c (AlturaTotal_C3, DiametroNormal_C3), ~ ifelse (.x >= 99999 , NA , .x)))
datos2 |>
filter (AlturaTotal_C3 >= 99999 | DiametroNormal_C3 >= 99999 )
# A tibble: 0 × 76
# ℹ 76 variables: UPMID <dbl>, IdConglomerado <dbl>, ArboladoID_C3 <dbl>,
# Anio_C3 <dbl>, Cve_Estado_C3 <dbl>, Estado_C3 <chr>, CVEECON1_C3 <dbl>,
# CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>, CVEECON4_C3 <chr>, DESECON1_C3 <chr>,
# DESECON2_C3 <chr>, DESECON3_C3 <chr>, DESECON4_C3 <chr>,
# Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>, X_C3 <dbl>, Y_C3 <dbl>,
# DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>, FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>,
# Sitio_C3 <dbl>, Consecutivo_C3 <dbl>, NoIndividuo_C3 <dbl>, …
Ya tenemos nuestros datos un poco más limpios. Veamos algunas estadísticas por grupo.
Agrupar y resumir
Para agrupar datos por algún nivel se usa group_by
. Al imprimir un tibble
con group_by
nos indica que está agrupado y nos dice el número de grupos.
datos <- datos |>
mutate (across (where (is.numeric), ~ ifelse (.x >= 99999 , NA , .x)))
datos |>
group_by (CVE_S7_C3)
# A tibble: 26,035 × 76
# Groups: CVE_S7_C3 [32]
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 40277 67761 NA 2019 16 Michoacán de Ocampo
2 40277 67761 NA 2019 16 Michoacán de Ocampo
3 40277 67761 NA 2019 16 Michoacán de Ocampo
4 40279 67762 NA 2015 16 Michoacán de Ocampo
5 40279 67762 NA 2015 16 Michoacán de Ocampo
6 40279 67762 NA 2015 16 Michoacán de Ocampo
7 40279 67762 NA 2015 16 Michoacán de Ocampo
8 40279 67762 NA 2015 16 Michoacán de Ocampo
9 40279 67762 NA 2015 16 Michoacán de Ocampo
10 40279 67762 NA 2015 16 Michoacán de Ocampo
# ℹ 26,025 more rows
# ℹ 70 more variables: CVEECON1_C3 <dbl>, CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>,
# CVEECON4_C3 <chr>, DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>,
# DESECON4_C3 <chr>, Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>,
# X_C3 <dbl>, Y_C3 <dbl>, DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>,
# FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>, Sitio_C3 <dbl>, Consecutivo_C3 <dbl>,
# NoIndividuo_C3 <dbl>, NoRama_C3 <dbl>, Azimut_C3 <dbl>, …
Para calcular nuevos valores se usa summarise
si se quiere resumir varias filas en una sola. summarise
quita todas las columnas que no sean grupos.
Para hacer conteos se puede usar count
o summarise(n = n())
En este ejemplo n()
calcula el número de filas por grupo.
datos |>
group_by (CVE_S7_C3) |>
count ()
# A tibble: 32 × 2
# Groups: CVE_S7_C3 [32]
CVE_S7_C3 n
<chr> <int>
1 AH 14
2 BA 354
3 BC 158
4 BM 153
5 BP 3099
6 BPQ 5513
7 BQ 1846
8 BQP 882
9 PC 181
10 PI 466
# ℹ 22 more rows
datos |>
group_by (CVE_S7_C3) |>
summarise (n = n ())
# A tibble: 32 × 2
CVE_S7_C3 n
<chr> <int>
1 AH 14
2 BA 354
3 BC 158
4 BM 153
5 BP 3099
6 BPQ 5513
7 BQ 1846
8 BQP 882
9 PC 181
10 PI 466
# ℹ 22 more rows
datos |>
group_by (CVE_S7_C3) |>
summarise (mean = mean (biomasa_kg_C3),
sd = sd (biomasa_kg_C3))
# A tibble: 32 × 3
CVE_S7_C3 mean sd
<chr> <dbl> <dbl>
1 AH 479. 1135.
2 BA 537. 973.
3 BC 99.6 165.
4 BM 230. 603.
5 BP 211. 649.
6 BPQ 210. 544.
7 BQ 116. 221.
8 BQP 194. 458.
9 PC 149. 559.
10 PI 45.9 61.6
# ℹ 22 more rows
Por default se quedan los datos agrupados a excepción del último nivel. Para quitarlos. Sugiero siempre poner .groups = "drop"
para que no se queden los datos agrupados. El que se queden los datos agrupados puede tener repercusiones no deseadas más abajo en la cadena de procesos. Revisar que el resultado no dice “groups” para asegurarnos que no se quedan agrupados. Mi recomendación es antes de hacer una operación agrupen para que esté muy claro la definición de grupos. También para desagrupar existe la función ungroup
.
Se puede agrupar los datos por el número de factores que se quieran.
Por ejemplo, veamos como cambian los resultados dejando los datos agrupados o no. En el primer caso se agrupan los datos por CVE_S7_C3, DESECON3_C3, mientras que en el segundo por ninguna variable.
datos |>
group_by (CVE_S7_C3, DESECON3_C3,DESECON4_C3) |>
summarise (mean = mean (biomasa_kg_C3),
sd = sd (biomasa_kg_C3)) |>
count ()
`summarise()` has grouped output by 'CVE_S7_C3', 'DESECON3_C3'. You can
override using the `.groups` argument.
# A tibble: 68 × 3
# Groups: CVE_S7_C3, DESECON3_C3 [68]
CVE_S7_C3 DESECON3_C3 n
<chr> <chr> <int>
1 AH Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 1
2 BA Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 1
3 BC Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 1
4 BM Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 1
5 BP Bosques de Coniferas, Encino y Mixtos de la Sierra Madre del… 1
6 BP Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 1
7 BPQ Depresion del Balsas con Selva Caducifolia y Matorral Xerofi… 1
8 BPQ Lomerios y Piedemontes del Pacifico Sur Mexicano con Selva E… 1
9 BPQ Lomerios y Planicies del Interior con Matorral Xerofilo y Bo… 1
10 BPQ Lomerios y Sierras con Bosques de Coniferas, Encino y Mixtos… 2
# ℹ 58 more rows
datos |>
group_by (CVE_S7_C3, DESECON3_C3, DESECON4_C3) |>
summarise (mean = mean (biomasa_kg_C3),
sd = sd (biomasa_kg_C3),
.groups = "drop" ) |>
count ()
# A tibble: 1 × 1
n
<int>
1 70
datos |>
group_by (CVE_S7_C3, DESECON3_C3,DESECON4_C3) |>
summarise (mean = mean (biomasa_kg_C3),
sd = sd (biomasa_kg_C3)) |>
ungroup () |>
count ()
`summarise()` has grouped output by 'CVE_S7_C3', 'DESECON3_C3'. You can
override using the `.groups` argument.
# A tibble: 1 × 1
n
<int>
1 70
datos |>
group_by (CVE_S7_C3, DESECON3_C3, DESECON4_C3) |>
summarise (mean = mean (biomasa_kg_C3),
sd = sd (biomasa_kg_C3),
.groups = "drop" ) |>
count ()
# A tibble: 1 × 1
n
<int>
1 70
Esto es biomasa promedio por árbol.
Para hacerlo por parcela:
datos |>
group_by (IdConglomerado) |>
summarise (AGB = sum (biomasa_kg_C3),
.groups = "drop" )
# A tibble: 348 × 2
IdConglomerado AGB
<dbl> <dbl>
1 56011 5220.
2 56504 690.
3 56794 156.
4 57005 3241.
5 57008 2246.
6 57259 17343.
7 57260 14427.
8 57274 4292.
9 57503 3504.
10 57512 4489.
# ℹ 338 more rows
Biomasa total por parcela (1600 m^2) Pasarlo a Mg/ha. Primero extrapolar de 1600 m^2 a 10 000 m^2 y luego de kg a Mg. Generar nueva columna con la biomasa por ha.
df_agb_sit <- datos |>
group_by (CVE_S7_C3, UPMID) |>
# Resumir por parcela
summarise (AGB = sum (biomasa_kg_C3),
.groups = "drop" ) |>
# Escalar a 1 ha. Parcelas son 1600 m2 de muestreo
mutate (scale = 10000 / 1600 ) |>
# Multiplicar por el factor de escalamiento
mutate (AGB.ha = AGB * scale) |>
# Transformar de kg a Mg.
mutate (across (AGB.ha, ~ .x/ 1000 ))
Ahora sí calcular el AGB promedio pr tipo de vegetación.
Alternativa para desagrupar: ungroup
df_agb_sit |>
group_by (CVE_S7_C3) |>
summarise (mean = mean (AGB.ha),
sd = sd (AGB.ha)) |>
ungroup ()
# A tibble: 32 × 3
CVE_S7_C3 mean sd
<chr> <dbl> <dbl>
1 AH 41.9 NA
2 BA 238. 204.
3 BC 49.2 6.33
4 BM 220. NA
5 BP 117. 72.3
6 BPQ 111. 79.1
7 BQ 58.4 36.8
8 BQP 97.3 64.1
9 PC 42.2 45.4
10 PI 19.1 7.38
# ℹ 22 more rows
Hay algunas que salen NA, seguramente porque hay NA en esas parcelas. No usarlas para los calculos
df_agb_sit |>
group_by (CVE_S7_C3) |>
summarise (mean = mean (AGB.ha, na.rm = TRUE ),
sd = sd (AGB.ha, na.rm = TRUE )) |>
ungroup ()
# A tibble: 32 × 3
CVE_S7_C3 mean sd
<chr> <dbl> <dbl>
1 AH 41.9 NA
2 BA 238. 204.
3 BC 49.2 6.33
4 BM 220. NA
5 BP 117. 72.3
6 BPQ 111. 79.1
7 BQ 58.4 36.8
8 BQP 97.3 64.1
9 PC 42.2 45.4
10 PI 19.1 7.38
# ℹ 22 more rows
Algunas tienen sd = NA, seguramente tienen un solo sitio de muestreo (no hay variación). Veamos con count
para contar
df_agb_sit |>
group_by (CVE_S7_C3) |>
count ()
# A tibble: 32 × 2
# Groups: CVE_S7_C3 [32]
CVE_S7_C3 n
<chr> <int>
1 AH 1
2 BA 5
3 BC 2
4 BM 1
5 BP 35
6 BPQ 65
7 BQ 23
8 BQP 11
9 PC 4
10 PI 7
# ℹ 22 more rows
Rebanar o sacar ciertas filas
Sacar valores más altos o más bajos por grupo se puede hacer con arrange
y slice
. O también existen las versiones slice_head
y slice_tail
.
df_agb_sit |>
group_by (CVE_S7_C3) |>
arrange (desc (AGB.ha)) |>
slice (1 )
# A tibble: 32 × 5
# Groups: CVE_S7_C3 [32]
CVE_S7_C3 UPMID AGB scale AGB.ha
<chr> <dbl> <dbl> <dbl> <dbl>
1 AH 73554 6701. 6.25 41.9
2 BA 74619 92682. 6.25 579.
3 BC 71551 8583. 6.25 53.6
4 BM 73604 35120. 6.25 220.
5 BP 70552 54020. 6.25 338.
6 BPQ 71523 66583. 6.25 416.
7 BQ 74589 25589. 6.25 160.
8 BQP 69510 39233. 6.25 245.
9 PC 42488 16929. 6.25 106.
10 PI 71509 5304. 6.25 33.1
# ℹ 22 more rows
Lo mismo, pero con slice_head
.
df_agb_sit |>
group_by (CVE_S7_C3) |>
arrange (desc (AGB.ha)) |>
slice_head (n = 1 )
# A tibble: 32 × 5
# Groups: CVE_S7_C3 [32]
CVE_S7_C3 UPMID AGB scale AGB.ha
<chr> <dbl> <dbl> <dbl> <dbl>
1 AH 73554 6701. 6.25 41.9
2 BA 74619 92682. 6.25 579.
3 BC 71551 8583. 6.25 53.6
4 BM 73604 35120. 6.25 220.
5 BP 70552 54020. 6.25 338.
6 BPQ 71523 66583. 6.25 416.
7 BQ 74589 25589. 6.25 160.
8 BQP 69510 39233. 6.25 245.
9 PC 42488 16929. 6.25 106.
10 PI 71509 5304. 6.25 33.1
# ℹ 22 more rows
Para pasar de un objeto tipo tibble a uno de tipo vector se puede hacer con pull
.
df_agb_sit |>
group_by (CVE_S7_C3) |>
arrange (desc (AGB.ha)) |>
slice_head (n = 1 ) |>
pull (AGB.ha)
[1] 41.881903 579.260686 53.646391 219.502453 337.624463 416.146763
[7] 159.930558 245.206817 105.803482 33.148318 2.293781 1.540609
[13] 32.690510 72.806867 66.026971 41.906103 18.885354 16.576570
[19] 36.662336 55.051676 87.933281 179.437483 156.779441 114.498957
[25] 56.464526 102.589533 67.534450 413.846176 89.985899 95.626391
[31] 161.376240 69.519826
Otras funciones útiles :
Algunas otras funciones de dplyr
.
rowwise. Hacer operaciones por cada fila.
bind_rows, bind_cols. Pegar listas por filas o por columnas. Función bastante útil para cuando tienes múltiples entradas con read.csv o algo similar.
any_of. Como all_of
pero para cuando quieres evaluar una condición sobre alguna en lugar de todas las variables.
left_join, right_join, full_join, anti_join. Útiles para unir dos tablas que comparten un campo en común. Diferentes formas de hacer estas uniones.
lag, lead. Para hacer operaciones “rolling”, por ejemplo, restar a cada valor el anterior o sumar. Usados para hacer sumas acumulativas.
Tidyr
Dos formatos principales en datos tabulados: largo (long) y ancho (wide). Hay dos funciones para cambiar rápida y fácilmente de un formato a otro:
Anidar y desanidar
Ahora si queremos meter datos dentro de una lista en un tibble se puede usar nest
.
datos |>
select (IdConglomerado,biomasa_kg_C3,DiametroNormal_C3) |>
pivot_longer (cols = - c (IdConglomerado),
names_to = "Variable" ,
values_to = "Valor" ) |>
pivot_wider (id_cols = c (IdConglomerado),
names_from = "Variable" ,
values_from = "Valor" ,
values_fn = list) |>
unnest_longer (c (biomasa_kg_C3, DiametroNormal_C3)) |>
group_by (IdConglomerado) |>
nest (data = biomasa_kg_C3)
# A tibble: 18,874 × 3
# Groups: IdConglomerado [348]
IdConglomerado DiametroNormal_C3 data
<dbl> <dbl> <list>
1 67761 7.9 <tibble [2 × 1]>
2 67761 41.2 <tibble [1 × 1]>
3 67761 11.2 <tibble [1 × 1]>
4 67761 9.4 <tibble [1 × 1]>
5 67761 7.7 <tibble [3 × 1]>
6 67761 10 <tibble [5 × 1]>
7 67761 8.2 <tibble [3 × 1]>
8 67761 8.7 <tibble [5 × 1]>
9 67761 12.4 <tibble [2 × 1]>
10 67761 14.9 <tibble [1 × 1]>
# ℹ 18,864 more rows
Y ahora veamos como podemos sacar los datos de una lista.
datos |>
select (IdConglomerado,biomasa_kg_C3,DiametroNormal_C3) |>
pivot_longer (cols = - c (IdConglomerado),
names_to = "Variable" ,
values_to = "Valor" ) |>
pivot_wider (id_cols = c (IdConglomerado),
names_from = "Variable" ,
values_from = "Valor" ,
values_fn = list) |>
unnest_longer (c (biomasa_kg_C3, DiametroNormal_C3)) |>
group_by (IdConglomerado) |>
nest (data = biomasa_kg_C3) |>
unnest (data)
# A tibble: 26,035 × 3
# Groups: IdConglomerado [348]
IdConglomerado DiametroNormal_C3 biomasa_kg_C3
<dbl> <dbl> <dbl>
1 67761 7.9 21.0
2 67761 7.9 17.0
3 67761 41.2 35.3
4 67761 11.2 10.5
5 67761 9.4 23.2
6 67761 7.7 9.42
7 67761 7.7 11.7
8 67761 7.7 7.25
9 67761 10 21.3
10 67761 10 20.0
# ℹ 26,025 more rows
Nest
y unnest
son útiles para hacer distintos modelos con diferentes grupos de datos o también para manejar casos no únicos al hacer pivot_wider.
Quitar NA
Hay otras funciones útiles en dplyr/tidyr para manejar datos con NA.
Quitar NA se hace con drop_na
datos |>
mutate (across (DiametroNormal_C3, ~ ifelse (.x >= 99999 , NA , .x))) |>
drop_na (DiametroNormal_C3)
# A tibble: 25,410 × 76
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 40277 67761 NA 2019 16 Michoacán de Ocampo
2 40277 67761 NA 2019 16 Michoacán de Ocampo
3 40277 67761 NA 2019 16 Michoacán de Ocampo
4 40279 67762 NA 2015 16 Michoacán de Ocampo
5 40279 67762 NA 2015 16 Michoacán de Ocampo
6 40279 67762 NA 2015 16 Michoacán de Ocampo
7 40279 67762 NA 2015 16 Michoacán de Ocampo
8 40279 67762 NA 2015 16 Michoacán de Ocampo
9 40279 67762 NA 2015 16 Michoacán de Ocampo
10 40279 67762 NA 2015 16 Michoacán de Ocampo
# ℹ 25,400 more rows
# ℹ 70 more variables: CVEECON1_C3 <dbl>, CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>,
# CVEECON4_C3 <chr>, DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>,
# DESECON4_C3 <chr>, Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>,
# X_C3 <dbl>, Y_C3 <dbl>, DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>,
# FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>, Sitio_C3 <dbl>, Consecutivo_C3 <dbl>,
# NoIndividuo_C3 <dbl>, NoRama_C3 <dbl>, Azimut_C3 <dbl>, …
Sustituir NA
A veces se desea sustituir los NA con algún valor. Eso se puede hacer con replace_na
.
datos |>
mutate (across (DiametroNormal_C3, ~ ifelse (.x >= 99999 , NA , .x))) |>
replace_na (list (DiametroNormal_C3 = 0 )) |>
filter (DiametroNormal_C3 == 0 )
# A tibble: 625 × 76
UPMID IdConglomerado ArboladoID_C3 Anio_C3 Cve_Estado_C3 Estado_C3
<dbl> <dbl> <dbl> <dbl> <dbl> <chr>
1 48449 65760 NA 2015 16 Michoacán de Ocampo
2 40287 67766 NA 2019 16 Michoacán de Ocampo
3 40289 67767 NA 2015 16 Michoacán de Ocampo
4 44863 66591 NA 2016 16 Michoacán de Ocampo
5 46036 66301 NA 2016 16 Michoacán de Ocampo
6 46132 66349 NA 2015 16 Michoacán de Ocampo
7 41362 67481 NA 2015 16 Michoacán de Ocampo
8 40287 67766 NA 2019 16 Michoacán de Ocampo
9 40287 67766 NA 2019 16 Michoacán de Ocampo
10 38204 68270 NA 2015 16 Michoacán de Ocampo
# ℹ 615 more rows
# ℹ 70 more variables: CVEECON1_C3 <dbl>, CVEECON2_C3 <dbl>, CVEECON3_C3 <chr>,
# CVEECON4_C3 <chr>, DESECON1_C3 <chr>, DESECON2_C3 <chr>, DESECON3_C3 <chr>,
# DESECON4_C3 <chr>, Region_Hidrologica_C3 <chr>, CVE_S7_C3 <chr>,
# X_C3 <dbl>, Y_C3 <dbl>, DESCRIP_S7_C3 <chr>, FORM_S7_C3 <chr>,
# FAO_S7_C3 <lgl>, ECO_S7_C3 <chr>, Sitio_C3 <dbl>, Consecutivo_C3 <dbl>,
# NoIndividuo_C3 <dbl>, NoRama_C3 <dbl>, Azimut_C3 <dbl>, …
Rellenar datos vacíos
Rellenar datos vación en función de las entradas que tienen próximas.
Veamos otros datos: - Recuento de especies conocidas de fauna por grupo de vertebrados y según categoría de riesgo de acuerdo con la NOM-059-ECOL-1994
Si no lo pueden descargar directamente de la página, bájenlo de mi repositorio de github: spNOM .
Trae unos signos extraños como nombre de columna.
Los datos muestran el número de especies por estado de riesgo de diferentes grupos de animales.
datos2 <- read_excel ("Data/spNOM.xlsx" ,
skip = 3 ,
na = "-" )
colnames (datos2)
[1] "\r\n\r\nCategoría"
[2] "\r\n\r\nGrupo"
[3] "\r\n\r\nEspecies conocidas"
[4] "\r\nEspecies \r\nEndémicas"
[5] "\r\nEspecies \r\namenazadas"
[6] "Especies \r\nen peligro \r\nde extinción"
[7] "\r\n\r\nEspecies raras"
[8] "\r\n\r\nProtección especial"
Vamos a usar un truco para quitar esos signos con str_replace_all
de los nombre de columnas de los datos.
Usaremos una función de otro paquete que no veremos a profundidad: stringr. Como \
es un caracter especial hay que usar doble `\\
para escaparlo.
nuevosnoms <- datos2 |>
colnames () |>
stringr:: str_replace_all (" \\ r \\ n \\ r \\ n| \\ r \\ n" , "" )
colnames (datos2) <- nuevosnoms
Ahora si podemos usar fill
para rellenar datos de una columna en particular y en el sentido indicado en .direction
.
datos2 |>
fill (all_of ("Categoría" ),
.direction = ("down" ))
# A tibble: 5 × 8
Categoría Grupo `Especies conocidas` `Especies Endémicas`
<chr> <chr> <dbl> <dbl>
1 Vertebrados Anfibios 290 174
2 Vertebrados Aves 1054 111
3 Vertebrados Mamíferos 491 142
4 Vertebrados Peces 2122 163
5 Vertebrados Reptiles 704 368
# ℹ 4 more variables: `Especies amenazadas` <dbl>,
# `Especies en peligro de extinción` <dbl>, `Especies raras` <dbl>,
# `Protección especial` <dbl>
Otras funciones útiles
Otras funciones útiles que ya no da tiempo de ver:
unite: unir dos columnas en una sol
separate: Separar una columna en dos o más usando un separador.
expand: Expandir a usar todas las combinacinoes posibles. Esto muchas veces es similar a usar pivot_wider
complete. Completa observaciones que no aparecen en los datos y los rellena con NA.
hoist: Es como un unnest para ciertas variables
rowwise: Aplicar una operación para cada fila.