Aumente su almacenamiento de datos con R
Publicado: 2022-03-11El lenguaje R a menudo se percibe como un lenguaje para estadísticos y científicos de datos. Hace bastante tiempo, esto era mayormente cierto. Sin embargo, a lo largo de los años, la flexibilidad que proporciona R a través de paquetes ha convertido a R en un lenguaje de propósito más general. R fue de código abierto en 1995 y, desde entonces, los repositorios de paquetes R están en constante crecimiento. Aún así, en comparación con lenguajes como Python, R se basa fuertemente en los datos.
Hablando de datos, los datos tabulares merecen especial atención, ya que es uno de los tipos de datos más utilizados. Es un tipo de datos que corresponde a una estructura de tabla conocida en las bases de datos, donde cada columna puede ser de un tipo diferente, y el rendimiento de procesamiento de ese tipo de datos en particular es el factor crucial para muchas aplicaciones.
En este artículo, vamos a presentar cómo lograr la transformación de datos tabulares de manera eficiente. Muchas personas que ya usan R para el aprendizaje automático no son conscientes de que la transferencia de datos se puede hacer más rápido en R y que no necesitan usar otra herramienta para ello.
Solución de alto rendimiento en R
Base R introdujo la clase data.frame
en el año 1997, que estaba basada en S-PLUS anterior. A diferencia de las bases de datos de uso común que almacenan datos fila por fila, R data.frame
almacena los datos en la memoria como una estructura orientada a columnas, lo que lo hace más eficiente en caché para las operaciones de columna que son comunes en el análisis. Además, aunque R es un lenguaje de programación funcional, no impone eso al desarrollador. Ambas oportunidades han sido bien abordadas por el paquete data.table
R, que está disponible en el repositorio CRAN. Funciona bastante rápido al agrupar operaciones y es particularmente eficiente con la memoria al tener cuidado al materializar subconjuntos de datos intermedios, como materializar solo aquellas columnas necesarias para una determinada tarea. También evita copias innecesarias a través de su semántica de referencia al agregar o actualizar columnas. La primera versión del paquete se publicó en abril de 2006, mejorando significativamente el rendimiento de data.frame
en ese momento. La descripción inicial del paquete era:
Este paquete hace muy poco. La única razón de su existencia es que el libro blanco especifica que data.frame debe tener nombres de fila. Este paquete define una nueva clase data.table que funciona como un data.frame, pero usa hasta 10 veces menos memoria y puede ser hasta 10 veces más rápido para crear (y copiar). También aprovecha la oportunidad para permitir subset() y with() como expresiones dentro de []. La mayor parte del código se copia de las funciones base y se elimina el código que manipula los nombres de las filas.
Desde entonces, se han mejorado las implementaciones de data.frame
y data.table
, pero data.table
sigue siendo increíblemente más rápida que la base R. De hecho, data.table
no solo es más rápida que la base R, sino que parece ser una de la herramienta de disputa de datos de código abierto más rápida disponible, que compite con herramientas como Python Pandas y bases de datos de almacenamiento en columnas o aplicaciones de big data como Spark. Su rendimiento sobre la infraestructura compartida distribuida aún no se ha evaluado, pero poder tener hasta dos mil millones de filas en una sola instancia ofrece perspectivas prometedoras. El rendimiento excepcional va de la mano con las funcionalidades. Además, con los esfuerzos recientes para paralelizar partes que consumen mucho tiempo para obtener ganancias de rendimiento incrementales, una dirección para empujar el límite de rendimiento parece bastante clara.
Ejemplos de transformación de datos
Aprender R se vuelve un poco más fácil debido al hecho de que funciona de forma interactiva, por lo que podemos seguir ejemplos paso a paso y ver los resultados de cada paso en cualquier momento. Antes de comenzar, instalemos el paquete data.table
desde el repositorio CRAN.
install.packages("data.table")
Sugerencia útil : podemos abrir el manual de cualquier función simplemente escribiendo su nombre con un signo de interrogación inicial, es decir, ?install.packages
.
Cargando datos en R
Hay toneladas de paquetes para extraer datos de una amplia gama de formatos y bases de datos, que a menudo incluyen controladores nativos. Cargaremos datos del archivo CSV , el formato más común para datos tabulares sin procesar. El archivo utilizado en los siguientes ejemplos se puede encontrar aquí. No tenemos que preocuparnos por el rendimiento de lectura de CSV
ya que la función fread
está altamente optimizada en eso.
Para usar cualquier función de un paquete, necesitamos cargarlo con la llamada a la library
.
library(data.table) DT <- fread("flights14.csv") print(DT)
## year month day dep_delay arr_delay carrier origin dest air_time ## 1: 2014 1 1 14 13 AA JFK LAX 359 ## 2: 2014 1 1 -3 13 AA JFK LAX 363 ## 3: 2014 1 1 2 9 AA JFK LAX 351 ## 4: 2014 1 1 -8 -26 AA LGA PBI 157 ## 5: 2014 1 1 2 1 AA JFK LAX 350 ## --- ## 253312: 2014 10 31 1 -30 UA LGA IAH 201 ## 253313: 2014 10 31 -5 -14 UA EWR IAH 189 ## 253314: 2014 10 31 -8 16 MQ LGA RDU 83 ## 253315: 2014 10 31 -4 15 MQ LGA DTW 75 ## 253316: 2014 10 31 -5 1 MQ LGA SDF 110 ## distance hour ## 1: 2475 9 ## 2: 2475 11 ## 3: 2475 19 ## 4: 1035 7 ## 5: 2475 13 ## --- ## 253312: 1416 14 ## 253313: 1400 8 ## 253314: 431 11 ## 253315: 502 11 ## 253316: 659 8
Si nuestros datos no están bien modelados para su posterior procesamiento, ya que deben cambiarse de formato de largo a ancho o de ancho a largo (también conocido como pivote y unpivot ), podemos ver ?dcast
y ?melt
, conocido del paquete reshape2. Sin embargo, data.table
implementa métodos más rápidos y eficientes en memoria para la clase data.table/data.frame.
Consultando con data.table
Sintaxis
Si está familiarizado con data.frame
Query data.table
es muy similar a query data.frame
. Al filtrar en el argumento i
, podemos usar los nombres de las columnas directamente sin necesidad de acceder a ellos con el signo $
, como df[df$col > 1, ]
. Al proporcionar el siguiente argumento j
, proporcionamos una expresión para ser evaluada en el ámbito de nuestra data.table
de datos. Para pasar un argumento j
que no sea una expresión, use with=FALSE
. El tercer argumento, no presente en el método data.frame
, define los grupos, haciendo que la expresión en j
sea evaluada por grupos.
# data.frame DF[DF$col1 > 1L, c("col2", "col3")] # data.table DT[col1 > 1L, .(col2, col3), ...] # by group using: `by = col4`
Si está familiarizado con las bases de datos
Query data.table
en muchos aspectos corresponde a consultas SQL con las que más personas pueden estar familiarizadas. El DT
a continuación representa el objeto data.table
y corresponde a la cláusula FROM
de SQL.
DT[ i = where, j = select | update, by = group by] [ having, ... ] [ order by, ... ] [ ... ] ... [ ... ]
Ordenar filas y reordenar columnas
La clasificación de datos es una transformación crucial para las series temporales, y también es importante para la extracción y presentación de datos. La ordenación se puede lograr proporcionando el vector entero del orden de las filas al argumento i
, de la misma manera que data.frame
. El primer argumento en order(carrier, -dep_delay)
seleccionará los datos en orden ascendente en el campo del carrier
y en orden descendente en la medida dep_delay
. El segundo argumento j
, como se describe en la sección anterior, define las columnas (o expresiones) que se devolverán y su orden.
ans <- DT[order(carrier, -dep_delay), .(carrier, origin, dest, dep_delay)] head(ans)
## carrier origin dest dep_delay ## 1: AA EWR DFW 1498 ## 2: AA JFK BOS 1241 ## 3: AA EWR DFW 1071 ## 4: AA EWR DFW 1056 ## 5: AA EWR DFW 1022 ## 6: AA EWR DFW 989
Para reordenar los datos por referencia, en lugar de consultar los datos en un orden específico, usamos funciones set*
.
setorder(DT, carrier, -dep_delay) leading.cols <- c("carrier","dep_delay") setcolorder(DT, c(leading.cols, setdiff(names(DT), leading.cols))) print(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## --- ## 253312: WN -12 2014 3 9 -21 LGA BNA 115 ## 253313: WN -13 2014 3 10 -18 EWR MDW 112 ## 253314: WN -13 2014 5 17 -30 LGA HOU 202 ## 253315: WN -13 2014 6 15 10 LGA MKE 101 ## 253316: WN -13 2014 8 19 -30 LGA CAK 63 ## distance hour ## 1: 1372 7 ## 2: 187 13 ## 3: 1372 10 ## 4: 1372 6 ## 5: 1372 7 ## --- ## 253312: 764 16 ## 253313: 711 20 ## 253314: 1428 17 ## 253315: 738 20 ## 253316: 397 16
La mayoría de las veces, no necesitamos tanto el conjunto de datos original como el conjunto de datos ordenado/ordenado. De forma predeterminada, el lenguaje R, similar a otros lenguajes de programación funcionales, devolverá los datos ordenados como un objeto nuevo y, por lo tanto, requerirá el doble de memoria que la clasificación por referencia.
Consultas de subconjunto
Vamos a crear un subconjunto de datos para el origen del vuelo "JFK" y el mes del 6 al 9. En el segundo argumento, subdividimos los resultados en las columnas enumeradas, agregando una variable calculada sum_delay
.
ans <- DT[origin == "JFK" & month %in% 6:9, .(origin, month, arr_delay, dep_delay, sum_delay = arr_delay + dep_delay)] head(ans)
## origin month arr_delay dep_delay sum_delay ## 1: JFK 7 925 926 1851 ## 2: JFK 8 727 772 1499 ## 3: JFK 6 466 451 917 ## 4: JFK 7 414 450 864 ## 5: JFK 6 411 442 853 ## 6: JFK 6 333 343 676
De forma predeterminada, al crear subconjuntos de conjuntos de datos en una sola columna, data.table
creará automáticamente un índice para esa columna. Esto da como resultado respuestas en tiempo real en cualquier otra llamada de filtrado en esa columna.
Actualizar conjunto de datos
La adición de una nueva columna por referencia se realiza mediante el operador :=
, asigna una variable al conjunto de datos en su lugar. Esto evita la copia en memoria del conjunto de datos, por lo que no necesitamos asignar resultados a cada nueva variable.
DT[, sum_delay := arr_delay + dep_delay] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: 187 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980
Para agregar más variables a la vez, podemos usar la sintaxis DT[,
:= (sum_delay = arr_delay + dep_delay)]
, similar a .(sum_delay = arr_delay + dep_delay)
al consultar desde un conjunto de datos.
Es posible subasignar por referencia, actualizando solo filas particulares en su lugar, simplemente combinándolas con el argumento i
.
DT[origin=="JFK", distance := NA] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay ## 1: 1372 7 2992 ## 2: NA 13 2464 ## 3: 1372 10 2135 ## 4: 1372 6 2171 ## 5: 1372 7 2095 ## 6: 1372 11 1980
Información agregada
Para agregar datos, proporcionamos el tercer argumento by
corchetes. Luego, en j
necesitamos proporcionar llamadas a funciones agregadas, para que los datos puedan agregarse realmente. El símbolo .N
utilizado en el argumento j
corresponde al número de todas las observaciones en cada grupo. Como se mencionó anteriormente, los agregados se pueden combinar con subconjuntos en filas y columnas de selección.
ans <- DT[, .(m_arr_delay = mean(arr_delay), m_dep_delay = mean(dep_delay), count = .N), .(carrier, month)] head(ans)
## carrier month m_arr_delay m_dep_delay count ## 1: AA 10 5.541959 7.591497 2705 ## 2: AA 4 1.903324 3.987008 2617 ## 3: AA 6 8.690067 11.476475 2678 ## 4: AA 9 -1.235160 3.307078 2628 ## 5: AA 8 4.027474 8.914054 2839 ## 6: AA 7 9.159886 11.665953 2802
A menudo, es posible que necesitemos comparar un valor de una fila con su agregado en un grupo. En SQL, aplicamos agregados sobre la partición por : AVG(arr_delay) OVER (PARTITION BY carrier, month)
.

ans <- DT[, .(arr_delay, carrierm_mean_arr = mean(arr_delay), dep_delay, carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(ans)
## carrier month arr_delay carrierm_mean_arr dep_delay carrierm_mean_dep ## 1: AA 10 1494 5.541959 1498 7.591497 ## 2: AA 10 840 5.541959 848 7.591497 ## 3: AA 10 317 5.541959 338 7.591497 ## 4: AA 10 292 5.541959 331 7.591497 ## 5: AA 10 322 5.541959 304 7.591497 ## 6: AA 10 306 5.541959 299 7.591497
Si no queremos consultar datos con esos agregados y, en su lugar, simplemente ponerlos en la actualización de la tabla real por referencia, podemos lograrlo con el operador :=
. Esto evita la copia en memoria del conjunto de datos, por lo que no es necesario asignar resultados a la nueva variable.
DT[, `:=`(carrierm_mean_arr = mean(arr_delay), carrierm_mean_dep = mean(dep_delay)), .(carrier, month)] head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep ## 1: 1372 7 2992 5.541959 7.591497 ## 2: NA 13 2464 1.903324 3.987008 ## 3: 1372 10 2135 8.690067 11.476475 ## 4: 1372 6 2171 -1.235160 3.307078 ## 5: 1372 7 2095 8.690067 11.476475 ## 6: 1372 11 1980 8.690067 11.476475
Unir conjuntos de datos
La combinación y combinación de bases R de conjuntos de datos se considera un tipo especial de operación de subconjunto . Proporcionamos un conjunto de datos al que queremos unirnos en el primer argumento de corchetes i
. Para cada fila en el conjunto de datos proporcionado a i
, hacemos coincidir las filas del conjunto de datos en el que usamos [
. Si queremos mantener solo las filas coincidentes ( unión interna ), entonces pasamos un argumento adicional nomatch = 0L
. Usamos on
argumento on para especificar columnas en las que queremos unir ambos conjuntos de datos.
# create reference subset carrierdest <- DT[, .(count=.N), .(carrier, dest) # count by carrier and dest ][1:10 # just 10 first groups ] # chaining `[...][...]` as subqueries print(carrierdest)
## carrier dest count ## 1: AA DFW 5877 ## 2: AA BOS 1173 ## 3: AA ORD 4798 ## 4: AA SEA 298 ## 5: AA EGE 85 ## 6: AA LAX 3449 ## 7: AA MIA 6058 ## 8: AA SFO 1312 ## 9: AA AUS 297 ## 10: AA DCA 172
# outer join ans <- carrierdest[DT, on = c("carrier","dest")] print(ans)
## carrier dest count dep_delay year month day arr_delay origin ## 1: AA DFW 5877 1498 2014 10 4 1494 EWR ## 2: AA BOS 1173 1241 2014 4 15 1223 JFK ## 3: AA DFW 5877 1071 2014 6 13 1064 EWR ## 4: AA DFW 5877 1056 2014 9 12 1115 EWR ## 5: AA DFW 5877 1022 2014 6 16 1073 EWR ## --- ## 253312: WN BNA NA -12 2014 3 9 -21 LGA ## 253313: WN MDW NA -13 2014 3 10 -18 EWR ## 253314: WN HOU NA -13 2014 5 17 -30 LGA ## 253315: WN MKE NA -13 2014 6 15 10 LGA ## 253316: WN CAK NA -13 2014 8 19 -30 LGA ## air_time distance hour sum_delay carrierm_mean_arr ## 1: 200 1372 7 2992 5.541959 ## 2: 39 NA 13 2464 1.903324 ## 3: 175 1372 10 2135 8.690067 ## 4: 198 1372 6 2171 -1.235160 ## 5: 178 1372 7 2095 8.690067 ## --- ## 253312: 115 764 16 -33 6.921642 ## 253313: 112 711 20 -31 6.921642 ## 253314: 202 1428 17 -43 22.875845 ## 253315: 101 738 20 -3 14.888889 ## 253316: 63 397 16 -43 7.219670 ## carrierm_mean_dep ## 1: 7.591497 ## 2: 3.987008 ## 3: 11.476475 ## 4: 3.307078 ## 5: 11.476475 ## --- ## 253312: 11.295709 ## 253313: 11.295709 ## 253314: 30.546453 ## 253315: 24.217560 ## 253316: 17.038047
# inner join ans <- DT[carrierdest, # for each row in carrierdest nomatch = 0L, # return only matching rows from both tables on = c("carrier","dest")] # joining on columns carrier and dest print(ans)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1071 2014 6 13 1064 EWR DFW 175 ## 3: AA 1056 2014 9 12 1115 EWR DFW 198 ## 4: AA 1022 2014 6 16 1073 EWR DFW 178 ## 5: AA 989 2014 6 11 991 EWR DFW 194 ## --- ## 23515: AA -8 2014 10 11 -13 JFK DCA 53 ## 23516: AA -9 2014 5 21 -12 JFK DCA 52 ## 23517: AA -9 2014 6 5 -6 JFK DCA 53 ## 23518: AA -9 2014 10 2 -21 JFK DCA 51 ## 23519: AA -11 2014 5 27 10 JFK DCA 55 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: 1372 10 2135 8.690067 11.476475 5877 ## 3: 1372 6 2171 -1.235160 3.307078 5877 ## 4: 1372 7 2095 8.690067 11.476475 5877 ## 5: 1372 11 1980 8.690067 11.476475 5877 ## --- ## 23515: NA 15 -21 5.541959 7.591497 172 ## 23516: NA 15 -21 4.150172 8.733665 172 ## 23517: NA 15 -15 8.690067 11.476475 172 ## 23518: NA 15 -30 5.541959 7.591497 172 ## 23519: NA 15 -1 4.150172 8.733665 172
Tenga en cuenta que, debido a la coherencia con el subconjunto R base, la combinación externa es de forma predeterminada RIGHT OUTER
. Si estamos buscando LEFT OUTER
, necesitamos intercambiar las tablas, como en el ejemplo anterior. El comportamiento exacto también se puede controlar fácilmente en el método merge
data.table
, utilizando la misma API que la base R merge
data.frame
.
Si queremos simplemente buscar la(s) columna(s) en nuestro conjunto de datos, podemos hacerlo de manera eficiente con el operador :=
en el argumento j
mientras nos unimos. De la misma manera que sub-asignamos por referencia, como se describe en la sección Actualizar conjunto de datos, ahora solo agregamos una columna por referencia del conjunto de datos al que nos unimos. Esto evita la copia de datos en memoria, por lo que no es necesario asignar resultados a nuevas variables.
DT[carrierdest, # data.table to join with lkp.count := count, # lookup `count` column from `carrierdest` on = c("carrier","dest")] # join by columns head(DT)
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: AA 1498 2014 10 4 1494 EWR DFW 200 ## 2: AA 1241 2014 4 15 1223 JFK BOS 39 ## 3: AA 1071 2014 6 13 1064 EWR DFW 175 ## 4: AA 1056 2014 9 12 1115 EWR DFW 198 ## 5: AA 1022 2014 6 16 1073 EWR DFW 178 ## 6: AA 989 2014 6 11 991 EWR DFW 194 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 1372 7 2992 5.541959 7.591497 5877 ## 2: NA 13 2464 1.903324 3.987008 1173 ## 3: 1372 10 2135 8.690067 11.476475 5877 ## 4: 1372 6 2171 -1.235160 3.307078 5877 ## 5: 1372 7 2095 8.690067 11.476475 5877 ## 6: 1372 11 1980 8.690067 11.476475 5877
Para agregar while join , use by = .EACHI
. Realiza una unión que no materializará resultados de unión intermedios y aplicará agregados sobre la marcha, lo que hace que sea eficiente en memoria.
Rolling join es una característica poco común, diseñada para manejar datos ordenados. Se adapta perfectamente al procesamiento de datos temporales y series temporales en general. Básicamente, hace rodar las coincidencias en condición de unión al siguiente valor coincidente. Úselo proporcionando el argumento roll
al unirse.
La combinación de superposición rápida une conjuntos de datos basados en períodos y su manejo superpuesto mediante el uso de varios operadores superpuestos: any
, within
de, start
, end
.
Actualmente se está desarrollando una función de unión no equitativa para unir conjuntos de datos utilizando condiciones desiguales.
Datos de perfil
Al explorar nuestro conjunto de datos, es posible que a veces deseemos recopilar información técnica sobre el tema para comprender mejor la calidad de los datos.
Estadísticas descriptivas
summary(DT)
## carrier dep_delay year month ## Length:253316 Min. :-112.00 Min. :2014 Min. : 1.000 ## Class :character 1st Qu.: -5.00 1st Qu.:2014 1st Qu.: 3.000 ## Mode :character Median : -1.00 Median :2014 Median : 6.000 ## Mean : 12.47 Mean :2014 Mean : 5.639 ## 3rd Qu.: 11.00 3rd Qu.:2014 3rd Qu.: 8.000 ## Max. :1498.00 Max. :2014 Max. :10.000 ## ## day arr_delay origin dest ## Min. : 1.00 Min. :-112.000 Length:253316 Length:253316 ## 1st Qu.: 8.00 1st Qu.: -15.000 Class :character Class :character ## Median :16.00 Median : -4.000 Mode :character Mode :character ## Mean :15.89 Mean : 8.147 ## 3rd Qu.:23.00 3rd Qu.: 15.000 ## Max. :31.00 Max. :1494.000 ## ## air_time distance hour sum_delay ## Min. : 20.0 Min. : 80.0 Min. : 0.00 Min. :-224.00 ## 1st Qu.: 86.0 1st Qu.: 529.0 1st Qu.: 9.00 1st Qu.: -19.00 ## Median :134.0 Median : 762.0 Median :13.00 Median : -5.00 ## Mean :156.7 Mean : 950.4 Mean :13.06 Mean : 20.61 ## 3rd Qu.:199.0 3rd Qu.:1096.0 3rd Qu.:17.00 3rd Qu.: 23.00 ## Max. :706.0 Max. :4963.0 Max. :24.00 Max. :2992.00 ## NA's :81483 ## carrierm_mean_arr carrierm_mean_dep lkp.count ## Min. :-22.403 Min. :-4.500 Min. : 85 ## 1st Qu.: 2.676 1st Qu.: 7.815 1st Qu.:3449 ## Median : 6.404 Median :11.354 Median :5877 ## Mean : 8.147 Mean :12.465 Mean :4654 ## 3rd Qu.: 11.554 3rd Qu.:17.564 3rd Qu.:6058 ## Max. : 86.182 Max. :52.864 Max. :6058 ## NA's :229797
Cardinalidad
Podemos verificar la unicidad de los datos usando la función uniqueN
y aplicarla en cada columna. El objeto .SD
en la consulta a continuación corresponde al subconjunto de la tabla de datos:
DT[, lapply(.SD, uniqueN)]
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 14 570 1 10 31 616 3 109 509 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 152 25 1021 134 134 11
Relación NA
Para calcular la proporción de valores desconocidos ( NA
en R y NULL
en SQL) para cada columna, proporcionamos la función deseada para aplicar en cada columna.
DT[, lapply(.SD, function(x) sum(is.na(x))/.N)]
## carrier dep_delay year month day arr_delay origin dest air_time ## 1: 0 0 0 0 0 0 0 0 0 ## distance hour sum_delay carrierm_mean_arr carrierm_mean_dep lkp.count ## 1: 0.3216654 0 0 0 0 0.9071555
Exportación de datos
El paquete data.table
también proporciona datos tabulares de exportación rápida a formato CSV
.
tmp.csv <- tempfile(fileext=".csv") fwrite(DT, tmp.csv) # preview exported data cat(system(paste("head -3",tmp.csv), intern=TRUE), sep="\n")
## carrier,dep_delay,year,month,day,arr_delay,origin,dest,air_time,distance,hour,sum_delay,carrierm_mean_arr,carrierm_mean_dep,lkp.count ## AA,1498,2014,10,4,1494,EWR,DFW,200,1372,7,2992,5.54195933456561,7.59149722735674,5877 ## AA,1241,2014,4,15,1223,JFK,BOS,39,,13,2464,1.90332441727168,3.98700802445548,1173
Al momento de escribir esto, la función fwrite
aún no se ha publicado en el repositorio CRAN. Para usarlo, necesitamos instalar la versión de desarrollo de data.table
, de lo contrario, podemos usar la función base R write.csv
, pero no espere que sea rápido.
Recursos
Hay muchos recursos disponibles. Además de los manuales disponibles para cada función, también hay viñetas de paquetes, que son tutoriales centrados en el tema en particular. Estos se pueden encontrar en la página Primeros pasos. Además, la página de presentaciones enumera más de 30 materiales (diapositivas, videos, etc.) de presentaciones de data.table
en todo el mundo. Además, el apoyo de la comunidad ha crecido a lo largo de los años, alcanzando recientemente la pregunta número 4000 en la etiqueta data.table
de desbordamiento de pila, y aún tiene una proporción alta (91,9 %) de preguntas respondidas. El siguiente gráfico presenta la cantidad de preguntas etiquetadas de data.table
en Stack Overflow a lo largo del tiempo.
Resumen
Este artículo proporciona ejemplos seleccionados para la transformación eficiente de datos tabulares en R mediante el paquete data.table
. Las cifras reales de rendimiento se pueden examinar buscando puntos de referencia reproducibles. Publiqué una publicación de blog resumida sobre las soluciones de data.table
para las 50 preguntas de StackOverflow mejor calificadas para el lenguaje R llamada Resuelva problemas comunes de R de manera eficiente con data.table, donde puede encontrar muchas cifras y código reproducible. El paquete data.table
utiliza la implementación nativa de la ordenación rápida de radix para sus operaciones de agrupación y la búsqueda binaria de subconjuntos/uniones rápidos. Este orden de radix se incorporó a la base R desde la versión 3.3.0. Además, el algoritmo se implementó recientemente en la plataforma de aprendizaje automático H2O y se paralelizó en el clúster H2O, lo que permitió grandes uniones eficientes en filas de 10B x 10B.