Importar y exportar datos

Crear un objeto data.table

Un objeto data.table se puede definir, por ejemplo:

library(data.table)

DT = data.table(
  ID = c("b","b","b","a","a","c"),
  a = 1:6,
  b = 7:12,
  c = 13:18
)

DT
       ID     a     b     c
   <char> <int> <int> <int>
1:      b     1     7    13
2:      b     2     8    14
3:      b     3     9    15
4:      a     4    10    16
5:      a     5    11    17
6:      c     6    12    18


Imaginemos que queremos crear una simulación de una base de datos de secuencias aleatorias. La tabla que queremos al final va a tener dos columnas, la primera es un número identificador de cada secuencia y la segunda la secuencia aleatoria de tamaño 300. Por ejemplo, la siguiente tabla muestra las primeras 10 filas del resultado esperado.

id sequencia
1 GCTCAGTCAACGACTAACCGCTCATAGGGAGGGGTCGAAATTAACCCCGCACACAGCCTTGGATAAGGGTCCAAGTCACGCAAGTTATATATAGTGACTG
2 TAACTCACAAGTTCTAATTCTCAATTGTTGGCCTTTTCAACGCATCTCCGATCGCGGTTTTGACTAAGACCAGCCGTTACCGTTGGTTATAGGGTCTCCC
3 TAAGACGGGGTATCTACATGATGTCCTTAAGTCCCATACCGCCCCCCCGCGAGTTGTCATTTAGAAAAGGTCAGTCATGCGTATCATTGGCATCCCCTAT
4 ATTTCACGTCGACGCTCCTTCTACAACGTCTGTCAGATCGCACGAATGCCGAGAAGGAGGAAGTATGGAGCGGTTTTGCGCCACATCCCTAATCCGCAGA
5 CAGCGAGGTGCTCTCACGGATACCCGGAGGAAAGCGGTGAAAAACTCTCGTACCTGCCCATTTCATCTTGACCGTACCCGTGACGGCGAATCAAAACGAG
6 GGTAGCTCCAAAAATTTCGTTAAGACATAGCAGCCTTATTACCCATGCCCGAAATTCGTTCAGTGTAGGGCACGTCCCACATGAGCGATCCGTGTAGTTT

Ejercicio: Genera un objeto data.table en el que la primera columna sea un id de secuencia y la segunda sea una secuencia (aleatoria) de tamaño 300 caracteres

secuencias <- data.table(
                id = seq(1,10000), 
                sequencia = sapply(seq(1, 10000), function(x) paste(sample(c("A", "T", "C", "G"), 100, replace = TRUE), collapse = "")))

head(secuencias)
      id                                                                                            sequencia
   <int>                                                                                               <char>
1:     1 TTCGGGGTGTATGAAACCCTGCTTAGTTTCGTTAGTCGCTTGGTCCCCCCTAGCTCAACATGGTTGGATTGAGCTCAGTTCAGGATCGGCATACAATAAC
2:     2 GATCAAGGATCCTGCTTGACTGTTTGAACTTTACTAGGATGTGCTTTTGGGTCTGGCACTACTGCAGGGTCGACCGGACCCCCACCTCGTAGAGTGTGAT
3:     3 ATTCGGTAGCAGTGATAGAGACGATTAGCCAGGATAGCCCGTGACATCTTACGTTCTTACAACACGTGTAAAGCCCTAGCGTTACCAAAGGAATAACCGA
4:     4 GCTGGGCACCCAGAATCGTTCTCGTGAATATGCACGCAGCACATCGAGCAACGACACCACCCGCCGTAGACCAATTACGACGGACGATAGAGAGCACGAT
5:     5 TTTTCTGCTAATTGGACAGCTCAACAATGCAAATACCACGCACGTCCTAAATTTCGCGAACGCTCAACGGACGTACAAGTCGCCATGTGAGCTGGCAGTT
6:     6 GCTACGATAATCTATTTTCCGTACATAGGCTGGACAAATCGGTACTCGCTGACTACTTGCTTACTATCCAGGCATCCAACATGGAATCGATTAATAGAGA


Importar y exportar datos de archivos

Las funciones para importar (fread) y exportar (fwrite) tienen las siguientes opciones principales:

  • x: el objeto que queremos exportar.

  • file: ruta para escribir/leer el archivo.

  • sep: el delimitador entre columnas.

Nota: La función tiene muchos argumentos que pueden ayudarte a personalizar el proceso de cargar datos en R.

Conjunto de datos

En esta y la siguiente sección vamos a trabajar una tabla de todos los especímenes de plantas que tiene registrados la plataforma GBIF (Global Biodiversity Information Facility) para México. Específicamente esta tabla solo contiene los registros de plantas que tienen un especímen guardado en alguna colección biológica y que tienen coordenadas que nos permitan ubicarlos.

Ejemplo: Por ejemplo, podemos importar la tabla original de plantae_mexico_conCoords_specimen.csv que tiene 3062756 registros y 50 filas.

Link para descargar la tabla completa. Descargarás una carpeta zip en donde viene el archivo de ocurrencias en formato Darwin Core (separado por comas)

Nota: fread() también permite leer archivos comprimidos .gz

library(data.table)

data = fread("data/plantae_mexico_conCoords_specimen.csv", quote="")

head(data) |> knitr::kable()
gbifID occurrenceID phylum class order family genus species infraspecificEpithet taxonRank scientificName verbatimScientificName verbatimScientificNameAuthorship countryCode stateProvince decimalLatitude decimalLongitude coordinateUncertaintyInMeters elevation day month year basisOfRecord
2825623524 TAIF:PLANT:318128:1:1:411555 Tracheophyta Polypodiopsida Polypodiales Pteridaceae Adiantum Adiantum andicola SPECIES Adiantum andicola Liebm. Adiantum andicola Liebm. NA MX Oaxaca (瓦哈卡州) 17.30213 -96.38080 NA 2267 27 2 2012 PRESERVED_SPECIMEN
2825649445 TAIF:PLANT:318579:1:1:411579 Tracheophyta Polypodiopsida Polypodiales Pteridaceae Scoliosorus Scoliosorus ensiformis SPECIES Scoliosorus ensiformis (Hook.) T.Moore Scoliosorus ensiformis (Hook.) T. Moore NA MX Oaxaca (瓦哈卡州) 17.30213 -96.38080 NA 2267 27 2 2012 PRESERVED_SPECIMEN
2825649446 TAIF:PLANT:318694:1:1:411603 Tracheophyta Polypodiopsida Polypodiales Polypodiaceae Pleopeltis Pleopeltis polylepis interjecta VARIETY Pleopeltis polylepis var. interjecta (Weath.) E.A.Hooper Pleopeltis polylepis (Roem. ex Kunze) T. Moore var. interjecta (Weath.) E. A. Hooper NA MX Oaxaca (瓦哈卡州) 17.38178 -96.44162 NA 2959 29 2 2012 PRESERVED_SPECIMEN
2825649447 TAIF:PLANT:318705:1:1:411602 Tracheophyta Polypodiopsida Polypodiales Aspleniaceae Asplenium Asplenium monanthes SPECIES Asplenium monanthes L. Asplenium monanthes L. NA MX Oaxaca (瓦哈卡州) 17.36213 -96.44678 NA 2820 29 2 2012 PRESERVED_SPECIMEN
2825649448 TAIF:PLANT:318740:1:1:411609 Tracheophyta Lycopodiopsida Lycopodiales Lycopodiaceae Diphasiastrum Diphasiastrum thyoides SPECIES Diphasiastrum thyoides (Humb. & Bonpl. ex Willd.) Holub Diphasiastrum thyoides (Humb. & Bonpl. ex Willd.) Holub NA MX Oaxaca (瓦哈卡州) 17.30213 -96.38080 NA 2267 27 2 2012 PRESERVED_SPECIMEN
2825649449 TAIF:PLANT:318741:1:1:411583 Tracheophyta Polypodiopsida Equisetales Equisetaceae Equisetum Equisetum praealtum affine VARIETY Equisetum hyemale var. affine (Engelm.) A.A.Eaton Equisetum hyemale L. var. affine (Engelm.) A. A. Eaton NA MX Oaxaca (瓦哈卡州) 17.35835 -96.44460 NA 2000 1 3 2012 PRESERVED_SPECIMEN


Utiliza el código anterior para cargar la tabla de especímenes en tu computadora.

Nota: La tabla tiene más de 3 millones de registros y, en las pruebas que hicimos, observamos que la tabla ocupa 1.72 GB de memoria cuando se carga. Incluimos un subconjunto aleatorio de 100,000 filas (sub_100000_plantae_mexico_conCoords_specimen.csv) para los que quieran practicar con objetos que ocupen menos memoria.

Exportar

data.table también tiene una función optimizada para escribir los datos con los que estamos trabajando en forma de archivo. Los argumentos básicos son:

  • x = objeto que se quiere exportar como archivo
  • file = nombre del archivo
  • sep = caracter que se quiere utilizar como delimitador de campo
  • compress = debido a que podríamos estar trabajando con tablas de datos muy grandes podemos escribir los archivos comprimidos. Se puede especificar “gzip” o “auto” y utilizar la extension .gz en el nombre del archivo para escribir un archivo comprimido, la opción “none” nos permite escribir archivos sin comprimir.

Ejemplo: podemos escribir la tabla DT que creamos al principio de la sección:

fwrite(DT, "data/testDT.csv", sep = ",")


Exporta la tabla de registros de especimenes como un archivo comprimido.

fwrite(data, "data/sub_100000_plantae_mexico_conCoords_specimen.csv.gz", sep = ",", compress = "auto")

Velocidad dplyr vs data.table


library(rbenchmark)

test = benchmark("r base" = {
            read.csv("big_data/plantae_mexico_conCoords_specimen.csv")
          },
          "data.table" = {
            fread("big_data/plantae_mexico_conCoords_specimen.csv")
          },
          replications = 10,
          columns = c("test", "replications", "elapsed",
                      "relative", "user.self", "sys.self"))

Nota: Si quieres correr este código revisa cuántas réplicas quieres hacer porque está escrito para leer la tabla de registros grande 10 veces utilizando cada método.

X test replications elapsed relative user.self sys.self
2 data.table 10 110.933 1.000 206.818 3.027
1 r base 10 380.665 3.431 376.605 4.057

Si quieres, puedes revisar el tiempo que te toma cargar la base de datos XX utilizando read.csv y fread. Utiliza el comando de benchmark de la paquetería rbenchmark para contar el tiempo. Nota: en el número de réplicas puedes poner una o dos porque si no te vas a tardar mucho.


data.frame - data.table

El objeto de data.table es un objeto basado en un data.frame, por lo tanto es compatible con las funciones de R base que trabajan con data.frame.

str(data)
Classes ‘data.table’ and 'data.frame':  3062756 obs. of  23 variables:
 $ gbifID                          :integer64 2825623524 2825649445 2825649446 2825649447 2825649448 2825649449 2825649452 2825649453 ... 
 $ occurrenceID                    : chr  "TAIF:PLANT:318128:1:1:411555" "TAIF:PLANT:318579:1:1:411579" "TAIF:PLANT:318694:1:1:411603" "TAIF:PLANT:318705:1:1:411602" ...
 $ phylum                          : chr  "Tracheophyta" "Tracheophyta" "Tracheophyta" "Tracheophyta" ...
 $ class                           : chr  "Polypodiopsida" "Polypodiopsida" "Polypodiopsida" "Polypodiopsida" ...
 $ order                           : chr  "Polypodiales" "Polypodiales" "Polypodiales" "Polypodiales" ...
 $ family                          : chr  "Pteridaceae" "Pteridaceae" "Polypodiaceae" "Aspleniaceae" ...
 $ genus                           : chr  "Adiantum" "Scoliosorus" "Pleopeltis" "Asplenium" ...
 $ species                         : chr  "Adiantum andicola" "Scoliosorus ensiformis" "Pleopeltis polylepis" "Asplenium monanthes" ...
 $ infraspecificEpithet            : chr  "" "" "interjecta" "" ...
 $ taxonRank                       : chr  "SPECIES" "SPECIES" "VARIETY" "SPECIES" ...
 $ scientificName                  : chr  "Adiantum andicola Liebm." "Scoliosorus ensiformis (Hook.) T.Moore" "Pleopeltis polylepis var. interjecta (Weath.) E.A.Hooper" "Asplenium monanthes L." ...
 $ verbatimScientificName          : chr  "Adiantum andicola Liebm." "Scoliosorus ensiformis (Hook.) T. Moore" "Pleopeltis polylepis (Roem. ex Kunze) T. Moore var. interjecta (Weath.) E. A. Hooper" "Asplenium monanthes L." ...
 $ verbatimScientificNameAuthorship: chr  "" "" "" "" ...
 $ countryCode                     : chr  "MX" "MX" "MX" "MX" ...
 $ stateProvince                   : chr  "Oaxaca (瓦哈卡州)" "Oaxaca (瓦哈卡州)" "Oaxaca (瓦哈卡州)" "Oaxaca (瓦哈卡州)" ...
 $ decimalLatitude                 : num  17.3 17.3 17.4 17.4 17.3 ...
 $ decimalLongitude                : num  -96.4 -96.4 -96.4 -96.4 -96.4 ...
 $ coordinateUncertaintyInMeters   : num  NA NA NA NA NA NA NA NA NA NA ...
 $ elevation                       : num  2267 2267 2959 2820 2267 ...
 $ day                             : int  27 27 29 29 27 1 27 27 5 1 ...
 $ month                           : int  2 2 2 2 2 3 2 2 5 3 ...
 $ year                            : int  2012 2012 2012 2012 2012 2012 2012 2012 2000 2012 ...
 $ basisOfRecord                   : chr  "PRESERVED_SPECIMEN" "PRESERVED_SPECIMEN" "PRESERVED_SPECIMEN" "PRESERVED_SPECIMEN" ...
 - attr(*, ".internal.selfref")=<externalptr> 
 - attr(*, "index")= int(0) 
  ..- attr(*, "__genus")= int [1:3062756] 419 423 490 494 513 514 521 542 571 585 ...

Sin embargo, los objetos se pueden cambiar de clase. Por ejemplo:

library(magrittr)

as.data.frame(DT) %>% class()
[1] "data.frame"
as.data.frame(DT) %>% as.data.table() %>% class()
[1] "data.table" "data.frame"