Buscar..


Introducción

Data.table es un paquete que amplía la funcionalidad de los marcos de datos desde la base R, particularmente mejorando su rendimiento y sintaxis. Consulte el área de documentos del paquete en Introducción a data.table para obtener más información.

Sintaxis

  • DT[i, j, by]
    # DT [donde, seleccione | actualizar | hacer, por]
  • DT[...][...]
    # encadenamiento
  • ################# Shortcuts, special functions and special symbols inside DT[...]
  • . ()
    # en varios argumentos, reemplaza lista ()
  • J ()
    # en i, reemplaza lista ()
  • : =
    # en j, una función utilizada para agregar o modificar columnas
  • .NORTE
    # en i, el número total de filas
    # en j, el número de filas en un grupo
  • .YO
    # en j, el vector de los números de fila en la tabla (filtrado por i)
  • .DAKOTA DEL SUR
    # en j, el subconjunto actual de los datos
    # seleccionado por el argumento .SDcols
  • .GRP
    # en j, el índice actual del subconjunto de los datos
  • .POR
    # en j, la lista de por valores para el subconjunto actual de datos
  • V1, V2, ...
    # nombres predeterminados para columnas sin nombre creadas en j
  • ################# Joins inside DT[...]
  • DT1 [DT2, on, j]
    # unir dos mesas
  • yo.*
    # prefijo especial en las columnas de DT2 después de la unión
  • por = .EACHI
    # opción especial disponible solo con una combinación
  • DT1 [! DT2, on, j]
    # anti-join dos mesas
  • DT1 [DT2, on, roll, j]
    # unir dos tablas, rodando en la última columna en on =
  • ################# Reshaping, stacking and splitting
  • derretir (DT, id.vars, measure.vars)
    # transformar a formato largo
    # para columnas múltiples, use measure.vars = patterns (...)
  • dcast (DT, formula)
    # transformar a formato ancho
  • rbind (DT1, DT2, ...)
    # pila enumeró data.tables
  • rbindlist (DT_list, idcol)
    # apilar una lista de data.tables
  • dividir (DT, por)
    # divide una tabla de datos en una lista
  • ################# Some other functions specialized for data.tables
  • foverlaps
    # superposición une
  • unir
    # Otra forma de unir dos mesas.
  • conjunto
    # Otra forma de agregar o modificar columnas.
  • fintersect, fsetdiff, funion, fsetequal, unique, duplicated, anyDuplicated
    # operaciones de set-theory con filas como elementos
  • únicoN
    # el número de filas distintas
  • rowidv (DT, cols)
    # ID de fila (1 a .N) dentro de cada grupo determinado por cols
  • rleidv (DT, cols)
    # ID de grupo (1 a .GRP) dentro de cada grupo determinado por ejecuciones de cols
  • shift (DT, n, type = c ("lag", "lead"))
    # aplicar un operador de turno a cada columna
  • setorder, setcolorder, setnames, setkey, setindex, setattr
    # modificar atributos y ordenar por referencia

Observaciones

Instalación y soporte

Para instalar el paquete data.table:

# install from CRAN
install.packages("data.table")       

# or install development version 
install.packages("data.table", type = "source", repos = "http://Rdatatable.github.io/data.table")

# and to revert from devel to CRAN, the current version must first be removed
remove.packages("data.table")
install.packages("data.table")

El sitio oficial del paquete tiene páginas wiki que proporcionan ayuda para comenzar, y listas de presentaciones y artículos de toda la web. Antes de hacer una pregunta, aquí en StackOverflow o en cualquier otro lugar, lea la página de soporte .

Cargando el paquete

Muchas de las funciones en los ejemplos anteriores existen en el espacio de nombres data.table. Para usarlos, primero deberá agregar una línea como library(data.table) o usar su ruta completa, como data.table::fread lugar de simplemente fread . Para obtener ayuda sobre funciones individuales, la sintaxis es help("fread") o ?fread . Nuevamente, si el paquete no está cargado, use el nombre completo como ?data.table::fread .

Creando una tabla de datos

Un data.table es una versión mejorada de la clase data.frame desde la base R. Como tal, su atributo class() es el vector "data.table" "data.frame" y las funciones que funcionan en un data.frame también Trabajar con una tabla de datos. Hay muchas formas de crear, cargar o forzar una tabla de datos.

Construir

No olvides instalar y activar el paquete data.table .

library(data.table)

Hay un constructor del mismo nombre:

DT <- data.table(
  x = letters[1:5], 
  y = 1:5, 
  z = (1:5) > 3
)
#    x y     z
# 1: a 1 FALSE
# 2: b 2 FALSE
# 3: c 3 FALSE
# 4: d 4  TRUE
# 5: e 5  TRUE

A diferencia de data.frame , data.table no data.table cadenas a factores:

sapply(DT, class)
#               x           y           z 
#     "character"   "integer"   "logical" 

Leer en

Podemos leer desde un archivo de texto:

dt <- fread("my_file.csv")

A diferencia de read.csv , fread leerá cadenas como cadenas, no como factores.

Modificar un data.frame

Para una mayor eficiencia, data.table ofrece una forma de alterar un data.frame o lista para hacer una data.table en el lugar (sin hacer una copia o cambiar su ubicación de memoria):

# example data.frame
DF <- data.frame(x = letters[1:5], y = 1:5, z = (1:5) > 3)
# modification
setDT(DF)

Tenga en cuenta que no <- asignamos el resultado, ya que el objeto DF se ha modificado in situ. Los atributos de clase del data.frame se mantendrán:

sapply(DF, class)
#         x         y         z 
#  "factor" "integer" "logical" 

Coercer objeto a data.table

Si tiene una list , data.frame o data.table , debe usar la función setDT para convertir a data.table porque realiza la conversión por referencia en lugar de hacer una copia (que as.data.table hace). Esto es importante si está trabajando con grandes conjuntos de datos.

Si tiene otro objeto R (como una matriz), debe usar as.data.table para as.data.table a una data.table .

mat <- matrix(0, ncol = 10, nrow = 10)

DT <- as.data.table(mat)
# or
DT <- data.table(mat)

Añadiendo y modificando columnas.

DT[where, select|update|do, by] sintaxis de DT[where, select|update|do, by] se utiliza para trabajar con columnas de una tabla de datos.

  • La parte "donde" es el argumento i
  • La parte "seleccionar | actualizar | hacer" es el argumento j

Estos dos argumentos generalmente se pasan por posición en lugar de por nombre.

Nuestro ejemplo de datos a continuación es

mtcars = data.table(mtcars, keep.rownames = TRUE)

Editando columnas enteras

Use el operador := dentro de j para asignar nuevas columnas:

mtcars[, mpg_sq := mpg^2]

Elimine las columnas estableciendo NULL :

mtcars[, mpg_sq := NULL]

Agregue varias columnas usando el formato multivariado del operador :=

mtcars[, `:=`(mpg_sq = mpg^2, wt_sqrt = sqrt(wt))]
# or 
mtcars[, c("mpg_sq", "wt_sqrt") := .(mpg^2, sqrt(wt))]

Si las columnas son dependientes y deben definirse en secuencia, una forma es:

mtcars[, c("mpg_sq", "mpg2_hp") := .(temp1 <- mpg^2, temp1/hp)]

La sintaxis .() Se usa cuando el lado derecho de LHS := RHS es una lista de columnas.

Para nombres de columna determinados dinámicamente, use paréntesis:

vn = "mpg_sq"
mtcars[, (vn) := mpg^2]

Las columnas también se pueden modificar con el set , aunque esto rara vez es necesario:

set(mtcars, j = "hp_over_wt", v = mtcars$hp/mtcars$wt)

Edición de subconjuntos de columnas

Utilice el argumento i para subcontratar a las filas "donde" se deben realizar las ediciones:

mtcars[1:3, newvar := "Hello"]
# or
set(mtcars, j = "newvar", i = 1:3, v = "Hello")  

Al igual que en un data.frame, podemos subcontratar utilizando números de fila o pruebas lógicas. También es posible utilizar una "unión" en i , pero en otro ejemplo se trata una tarea más complicada.

Edición de atributos de columna

Las funciones que editan atributos, como los levels<- o names<- , reemplazan un objeto con una copia modificada. Incluso si solo se utiliza en una columna en una tabla de datos, todo el objeto se copia y se reemplaza.

Para modificar un objeto sin copias, use setnames para cambiar los nombres de columna de data.table o data.frame y setattr para cambiar un atributo para cualquier objeto.

# Print a message to the console whenever the data.table is copied
tracemem(mtcars)
mtcars[, cyl2 := factor(cyl)]

# Neither of these statements copy the data.table
setnames(mtcars, old = "cyl2", new = "cyl_fac")
setattr(mtcars$cyl_fac, "levels", c("four", "six", "eight"))

# Each of these statements copies the data.table
names(mtcars)[names(mtcars) == "cyl_fac"] <- "cf"
levels(mtcars$cf) <- c("IV", "VI", "VIII")

Tenga en cuenta que estos cambios se realizan por referencia, por lo que son globales . Cambiarlos dentro de un entorno afecta al objeto en todos los entornos.

# This function also changes the levels in the global environment
edit_levels <- function(x) setattr(x, "levels", c("low", "med", "high"))
edit_levels(mtcars$cyl_factor)

Símbolos especiales en tabla de datos.

.DAKOTA DEL SUR

.SD refiere al subconjunto de la data.table de data.table para cada grupo, excluyendo todas las columnas utilizadas by .

.SD junto con lapply se puede usar para aplicar cualquier función a varias columnas por grupo en una data.table

Continuaremos usando el mismo conjunto de datos mtcars , mtcars :

mtcars = data.table(mtcars) # Let's not include rownames to keep things simpler

Media de todas las columnas en el conjunto de datos por número de cilindros , cyl :

mtcars[ , lapply(.SD, mean), by = cyl]

#   cyl      mpg     disp        hp     drat       wt     qsec        vs        am     gear     carb
#1:   6 19.74286 183.3143 122.28571 3.585714 3.117143 17.97714 0.5714286 0.4285714 3.857143 3.428571
#2:   4 26.66364 105.1364  82.63636 4.070909 2.285727 19.13727 0.9090909 0.7272727 4.090909 1.545455
#3:   8 15.10000 353.1000 209.21429 3.229286 3.999214 16.77214 0.0000000 0.1428571 3.285714 3.500000

Aparte de cyl , hay otras columnas categóricas en el conjunto de datos como vs , am , gear y carb . Realmente no tiene sentido tomar la mean de estas columnas. Así que vamos a excluir estas columnas. Aquí es donde .SDcols entra en escena.

.SDcols

.SDcols especifica las columnas de la data.table que se incluyen en .SD .

La media de todas las columnas (columnas continuas) en el conjunto de datos por número de engranajes gear , y el número de cilindros, cyl , dispuestos por gear y cyl :

# All the continuous variables in the dataset
cols_chosen <- c("mpg", "disp", "hp", "drat", "wt", "qsec")

mtcars[order(gear, cyl), lapply(.SD, mean), by = .(gear, cyl), .SDcols = cols_chosen]

#   gear cyl    mpg     disp       hp     drat       wt    qsec
#1:    3   4 21.500 120.1000  97.0000 3.700000 2.465000 20.0100
#2:    3   6 19.750 241.5000 107.5000 2.920000 3.337500 19.8300
#3:    3   8 15.050 357.6167 194.1667 3.120833 4.104083 17.1425
#4:    4   4 26.925 102.6250  76.0000 4.110000 2.378125 19.6125
#5:    4   6 19.750 163.8000 116.5000 3.910000 3.093750 17.6700
#6:    5   4 28.200 107.7000 102.0000 4.100000 1.826500 16.8000
#7:    5   6 19.700 145.0000 175.0000 3.620000 2.770000 15.5000
#8:    5   8 15.400 326.0000 299.5000 3.880000 3.370000 14.5500

Tal vez no queremos calcular la mean por grupos. Para calcular la media de todos los autos en el conjunto de datos, no especificamos la variable by .

mtcars[ , lapply(.SD, mean), .SDcols = cols_chosen] 

#        mpg     disp       hp     drat      wt     qsec
#1: 20.09062 230.7219 146.6875 3.596563 3.21725 17.84875

Nota:

  • No es necesario definir cols_chosen antemano. .SDcols puede tomar directamente nombres de columna
  • .SDcols también puede tomar directamente un vector de números de columna. En el ejemplo anterior, esto sería mtcars[ , lapply(.SD, mean), .SDcols = c(1,3:7)]

.NORTE

.N es una abreviatura de la cantidad de filas en un grupo.

iris[, .(count=.N), by=Species]

#      Species count
#1:     setosa    50
#2: versicolor    50
#3:  virginica    50

Escribir código compatible tanto con data.frame como con data.table

Diferencias en la sintaxis del subconjunto.

A data.table es una de varias estructuras de datos bidimensionales disponibles en R, además de data.frame , matrix y (2D) array . Todas estas clases utilizan una sintaxis muy similar pero no idéntica para la subconjunto, el esquema A[rows, cols] .

Considere los siguientes datos almacenados en una matrix , un data.frame y un data.table :

ma <- matrix(rnorm(12), nrow=4, dimnames=list(letters[1:4], c('X', 'Y', 'Z')))
df <- as.data.frame(ma)
dt <- as.data.table(ma)

ma[2:3]  #---> returns the 2nd and 3rd items, as if 'ma' were a vector (because it is!)
df[2:3]  #---> returns the 2nd and 3rd columns
dt[2:3]  #---> returns the 2nd and 3rd rows!

Si desea estar seguro de lo que se devolverá, es mejor ser explícito .

Para obtener filas específicas, solo agregue una coma después del rango:

ma[2:3, ]  # \
df[2:3, ]  #  }---> returns the 2nd and 3rd rows
dt[2:3, ]  # /

Pero, si desea subcontratar columnas , algunos casos se interpretan de manera diferente. Los tres pueden ser subconjuntos de la misma manera con índices enteros o de caracteres no almacenados en una variable.

ma[, 2:3]          #  \
df[, 2:3]          #   \
dt[, 2:3]          #    }---> returns the 2nd and 3rd columns
ma[, c("Y", "Z")]  #   /
df[, c("Y", "Z")]  #  /
dt[, c("Y", "Z")]  # /

Sin embargo, difieren para nombres de variables sin comillas

mycols <- 2:3
ma[, mycols]                # \
df[, mycols]                #  }---> returns the 2nd and 3rd columns
dt[, mycols, with = FALSE]  # /

dt[, mycols]                # ---> Raises an error

En el último caso, mycols se evalúa como el nombre de una columna. Debido a que dt no puede encontrar una columna llamada mycols , se mycols un error.

Nota: Para las versiones de la data.table paquete priorto 1.9.8, este comportamiento fue un poco diferente. Cualquier cosa en el índice de la columna habría sido evaluada utilizando dt como un entorno. Entonces, tanto dt[, 2:3] como dt[, mycols] devolverían el vector 2:3 . No se mycols ningún error para el segundo caso, porque la variable mycols existe en el entorno principal.

Estrategias para mantener la compatibilidad con data.frame y data.table.

Hay muchas razones para escribir código que está garantizado para trabajar con data.frame y data.table . Tal vez se vea obligado a usar data.frame , o tal vez necesite compartir un código que no sabe cómo se usará. Por lo tanto, hay algunas estrategias principales para lograr esto, en orden de conveniencia:

  1. Utilice la sintaxis que se comporta de la misma manera para ambas clases.
  2. Utilice una función común que haga lo mismo que la sintaxis más corta.
  3. Forzar data.table para que se comporte como data.frame (ej .: llamar al método específico print.data.frame ).
  4. Trátelos como list , que son en última instancia.
  5. Convierta la tabla en un data.frame antes de hacer cualquier cosa (mala idea si es una tabla enorme).
  6. Convierta la tabla a data.table , si las dependencias no son una preocupación.

Subconjunto de filas. Es simple, solo use el selector [, ] , con la coma:

A[1:10, ]
A[A$var > 17, ]  # A[var > 17, ] just works for data.table

Subconjuntar columnas. Si desea una sola columna, use el selector $ o [[ ]] :

A$var
colname <- 'var'
A[[colname]]
A[[1]]

Si desea una forma uniforme de capturar más de una columna, es necesario apelar un poco:

B <- `[.data.frame`(A, 2:4)

# We can give it a better name
select <- `[.data.frame`
B <- select(A, 2:4)
C <- select(A, c('foo', 'bar'))

Subconjunto de filas 'indexadas'. Mientras que data.frame tiene row.names , data.table tiene su característica key única. Lo mejor es evitar row.names completo row.names y aprovechar las optimizaciones existentes en el caso de data.table cuando sea posible.

B <- A[A$var != 0, ]
# or...
B <- with(A, A[var != 0, ])  # data.table will silently index A by var before subsetting

stuff <- c('a', 'c', 'f')
C <- A[match(stuff, A$name), ]  # really worse than: setkey(A); A[stuff, ]

Obtener una tabla de 1 columna, obtener una fila como un vector. Estos son fáciles con lo que hemos visto hasta ahora:

B <- select(A, 2)    #---> a table with just the second column
C <- unlist(A[1, ])  #---> the first row as a vector (coerced if necessary)

Configuración de teclas en data.table

Sí, necesitas SETKEY pre 1.9.6

En el pasado (anterior a 1.9.6), su data.table se aceleró al establecer columnas como claves de la tabla, particularmente para tablas grandes. [Vea la introducción en la página 5 de la versión de septiembre de 2015, donde la velocidad de búsqueda fue 544 veces mejor.] Puede encontrar códigos más antiguos que utilizan estas teclas de configuración con la tecla 'setkey' o una columna 'key =' al configurar la tabla.

library(data.table)
DT <- data.table(
  x = letters[1:5], 
  y = 5:1, 
  z = (1:5) > 3
)

#> DT
#   x y     z
#1: a 5 FALSE
#2: b 4 FALSE
#3: c 3 FALSE
#4: d 2  TRUE
#5: e 1  TRUE

Establece tu clave con el comando setkey . Puedes tener una clave con múltiples columnas.

setkey(DT, y)

Verifique la llave de su mesa en tablas ()

tables()

> tables()
     NAME NROW NCOL MB COLS  KEY
[1,] DT      5    3  1 x,y,z y  
Total: 1MB

Tenga en cuenta que esto reordena sus datos.

#> DT
#   x y     z
#1: e 1  TRUE
#2: d 2  TRUE
#3: c 3 FALSE
#4: b 4 FALSE
#5: a 5 FALSE

Ahora es innecesario

Antes de v1.9.6 tenía que haber establecido una clave para ciertas operaciones, especialmente para unir tablas. Los desarrolladores de data.table han acelerado e introducido una función "on=" que puede reemplazar la dependencia de las claves. Vea SO aquí para una discusión detallada.

En enero de 2017, los desarrolladores escribieron una viñeta alrededor de los índices secundarios que explica la sintaxis "on" y permite que se identifiquen otras columnas para una indexación rápida.

¿Creando índices secundarios?

De una manera similar a la clave, puede establecer setindex(DT, key.col) o setindexv(DT, "key.col.string") , donde DT es su tabla de datos. Eliminar todos los índices con setindex(DT, NULL) .

Consulte sus índices secundarios con indices(DT) .

¿Por qué índices secundarios?

Esto no ordena la tabla (a diferencia de la clave), pero permite una indexación rápida utilizando la sintaxis "on". Tenga en cuenta que solo puede haber una clave, pero puede usar múltiples índices secundarios, lo que ahorra tener que cambiar la configuración de la tabla. Esto acelerará su subconjunto cuando cambie las columnas en las que desea subconjuntar.

Recuerde, en el ejemplo anterior y fue la clave para la tabla DT:

DT
# x y     z
# 1: e 1  TRUE
# 2: d 2  TRUE
# 3: c 3 FALSE
# 4: b 4 FALSE
# 5: a 5 FALSE

# Let us set x as index 
setindex(DT, x)

# Use indices to see what has been set
indices(DT)
# [1] "x"

# fast subset using index and not keyed column
DT["c", on ="x"]
#x y     z
#1: c 3 FALSE

# old way would have been rekeying DT from y to x, doing subset and 
# perhaps keying back to y (now we save two sorts)
# This is a toy example above but would have been more valuable with big data sets


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow