¿Cómo se elimina una columna por nombre en data.table?


195

Para deshacerme de una columna llamada "foo" en un data.frame, puedo hacer:

df <- df[-grep('foo', colnames(df))]

Sin embargo, una vez dfse convierte en undata.table objeto, no hay forma de eliminar una columna.

Ejemplo:

df <- data.frame(id = 1:100, foo = rnorm(100))
df2 <- df[-grep('foo', colnames(df))] # works
df3 <- data.table(df)
df3[-grep('foo', colnames(df3))] 

Pero una vez que se convierte en un data.tableobjeto, esto ya no funciona.


2
Hubiera sido más claro nombrar data.table en dtlugar de df3...
PatrickT

Respuestas:


283

Cualquiera de los siguientes eliminará la columna foode data.table df3:

# Method 1 (and preferred as it takes 0.00s even on a 20GB data.table)
df3[,foo:=NULL]

df3[, c("foo","bar"):=NULL]  # remove two columns

myVar = "foo"
df3[, (myVar):=NULL]   # lookup myVar contents

# Method 2a -- A safe idiom for excluding (possibly multiple)
# columns matching a regex
df3[, grep("^foo$", colnames(df3)):=NULL]

# Method 2b -- An alternative to 2a, also "safe" in the sense described below
df3[, which(grepl("^foo$", colnames(df3))):=NULL]

data.table también admite la siguiente sintaxis:

## Method 3 (could then assign to df3, 
df3[, !"foo"]  

aunque si en realidad estaban esperando para extraer la columna "foo"de df3(en lugar de sólo la impresión de una vista de df3la columna menos "foo") que realmente te quiere utilizar el método 1 en su lugar.

(Tenga en cuenta que si utiliza un método que se basa en grep()o grepl(), debe establecerlo en pattern="^foo$"lugar de hacerlo "foo", si no desea que las columnas con nombres como "fool"y "buffoon"(es decir, las que contienen foocomo una subcadena) también coincidan y se eliminen).

Opciones menos seguras, bien para uso interactivo:

Los siguientes dos modismos también funcionarán, si df3contiene una coincidencia de columna"foo" , pero fallarán de una manera probablemente inesperada si no lo hace. Si, por ejemplo, usa alguno de ellos para buscar la columna inexistente "bar", terminará con una tabla de datos de fila cero.

Como consecuencia, son realmente más adecuados para el uso interactivo donde uno podría, por ejemplo, querer mostrar una tabla de datos menos cualquier columna con nombres que contengan la subcadena "foo". Para fines de programación (o si realmente desea eliminar la (s) columna (s) en df3lugar de una copia de ella), los Métodos 1, 2a y 2b son realmente las mejores opciones.

# Method 4:
df3[, .SD, .SDcols = !patterns("^foo$")]

Por último, hay enfoques que usan with=FALSE, aunque data.tablegradualmente se aleja del uso de este argumento, por lo que ahora se desaconseja dónde puede evitarlo; que se muestra aquí para que sepa que la opción existe en caso de que realmente la necesite:

# Method 5a (like Method 3)
df3[, !"foo", with=FALSE] 
# Method 5b (like Method 4)
df3[, !grep("^foo$", names(df3)), with=FALSE]
# Method 5b (another like Method 4)
df3[, !grepl("^foo$", names(df3)), with=FALSE]

2
Vea mi comentario al OP con respecto a -grepversus !grepl.
Joshua Ulrich

1
@JoshuaUlrich - Buen punto. Lo intenté grepl()inicialmente y no funcionó, ya que las columnas data.table no pueden ser indexadas por un vector lógico. Pero ahora me doy cuenta de que grepl()se puede hacer que funcione envolviéndolo which(), para que devuelva un vector entero.
Josh O'Brien

1
No sabía eso sobre la indexación data.table, ¡pero envolverlo whiches inteligente!
Joshua Ulrich

66
Yo tampoco sabía eso data.table; añadido FR # 1797 . Pero, el método 1 es (casi) infinitamente más rápido que los demás. El método 1 elimina la columna por referencia sin ninguna copia. Dudo que lo consigas por encima de 0.005 segundos para cualquier tabla de datos de tamaño. Por el contrario, los otros podrían no funcionar si la tabla está cerca del 50% de RAM porque copian todos menos el que se va a eliminar.
Matt Dowle

1
@ user3969377 si desea eliminar una columna basada en el contenido de una variable de caracteres, simplemente la envolverá entre paréntesis. Es decir. df [, (afoo): = NULL]
Dean MacGregor

31

También puede usar setpara esto, que evita la sobrecarga de los [.data.tablebucles:

dt <- data.table( a=letters, b=LETTERS, c=seq(26), d=letters, e=letters )
set( dt, j=c(1L,3L,5L), value=NULL )
> dt[1:5]
   b d
1: A a
2: B b
3: C c
4: D d
5: E e

Si desea hacerlo por nombre de columna, which(colnames(dt) %in% c("a","c","e"))debería funcionar para j.


2
En data.table1.11.8, si desea hacerlo por nombre de columna, puede hacerlo directamente rm.col = c("a","b")ydt[, (rm.col):=NULL]
Duccio A

20

Simplemente lo hago en el tipo de marco de datos:

DT$col = NULL

Funciona rápido y, por lo que pude ver, no causa ningún problema.

ACTUALIZACIÓN: no es el mejor método si su DT es muy grande, ya que el uso del $<-operador conducirá a la copia de objetos. Así que mejor uso:

DT[, col:=NULL]

8

Opción muy simple en caso de que tenga muchas columnas individuales para eliminar en una tabla de datos y desee evitar escribir todos los nombres de columna #careadviced

dt <- dt[, -c(1,4,6,17,83,104)]

Esto eliminará columnas basadas en el número de columna en su lugar.

Obviamente no es tan eficiente porque evita las ventajas de data.table, pero si está trabajando con menos de 500,000 filas, funciona bien


4

Suponga que su DT tiene columnas col1, col2, col3, col4, col5, coln.

Para eliminar un subconjunto de ellos:

vx <- as.character(bquote(c(col1, col2, col3, coln)))[-1]
DT[, paste0(vx):=NULL]

esto debería ser un comentario
Sachila Ranawaka

-2

Aquí hay una forma en que desea establecer un número de columnas en NULL, dado que sus nombres de columnas son una función para su uso :)

deleteColsFromDataTable <- function (train, toDeleteColNames) {

       for (myNm in toDeleteColNames)

       train <- train [,(myNm):=NULL]

       return (train)
}


-7

Para un data.table, la asignación de la columna a NULL lo elimina:

DT[,c("col1", "col1", "col2", "col2")] <- NULL
^
|---- Notice the extra comma if DT is a data.table

... que es el equivalente de:

DT$col1 <- NULL
DT$col2 <- NULL
DT$col3 <- NULL
DT$col4 <- NULL

El equivalente para un data.frame es:

DF[c("col1", "col1", "col2", "col2")] <- NULL
      ^
      |---- Notice the missing comma if DF is a data.frame

P. ¿Por qué hay una coma en la versión para data.table y ninguna coma en la versión para data.frame?

A. Como data.frames se almacenan como una lista de columnas, puede omitir la coma. También puede agregarlo, sin embargo, deberá asignarlos a una lista de NULLs DF[, c("col1", "col2", "col3")] <- list(NULL),.


@Arun No se me ocurre ninguna situación data.framesen la que se cambiarían la fila y las columnas. Eso sería ilógico.
duHaas

@Arun Te etiqueté porque tu primer comentario hizo que pareciera que había momentos en los que podrías llamar, DF[column,row]así que solo quería ver si realmente hubo casos en los que esto sucedió.
duHaas

Se actualizó la respuesta para eliminar un error tipográfico.
Contango
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.