2012-02-10 14 views
28

Tengo un data.table con las columnas 2 a la 20 como cadenas con espacios (por ejemplo, "Nombre de la especie"). Deseo ejecutar str_replace() en todas esas columnas simultáneamente para que todo el "Nombre de la especie" se convierta en "Nombre_especie". Puedo hacer cualquiera:¿Cómo ejecuto apply en data.table?

data.table(apply(as.data.frame(dt[,2:dim(dt)[2], with=F]), 2, 
           function(x){ str_replace(x," ","_") })) 

o si lo guardo como un objeto data.table, entonces yo puedo hacer esto una columna a la vez:

dt[,SpeciesName := str_replace(SpeciesName, " ", "_") 

¿Cómo se hace esto para todas las columnas 2 a el final similar al de arriba?

Respuesta

30

diseño totalmente renovado en el 24/11/2015, para corregir un error en las versiones anteriores.

Tiene algunas opciones.

  1. Proceso de todas las columnas de destino con un componente implícito a lapply(), utilizando := para asignar los valores modificados en su lugar. Este se basa en el muy útil soporte de := para la asignación simultánea a varias columnas nombradas en su LHS.

  2. utilizar un bucle for para ejecutar a través de las columnas de destino de una en una, usando set() para modificar el valor de cada uno a su vez.

  3. utilizar un bucle for para iterar sobre múltiples "naive" pide a [.data.table(), cada uno de los cuales modifica una sola columna.

Estos métodos parecen todos sobre la misma velocidad, por lo que se utiliza se ser sobre todo una cuestión de gusto. (1) es muy compacto y expresivo. Es lo que uso con más frecuencia, aunque puede encontrar (2) más fácil de leer. Debido a que procesan y modifican las columnas de a una por vez, (2) o (3) tendrán una ventaja en la rara situación en la que su data.table sea tan grande que corra peligro de toparse con los límites impuestos por su La memoria disponible de la sesión R

library(data.table) 

## Create three identical 1000000-by-20 data.tables 
DT1 <- data.table(1:1e6, 
      as.data.table(replicate(1e6, paste(sample(letters, nr, TRUE), 
              sample(letters, nr, TRUE))))) 
cnames <- c("ID", paste0("X", 1:19)) 
setnames(DT1, cnames) 
DT2 <- copy(DT1); DT3 <- copy(DT1) 

## Method 1 
system.time({ 
DT1[, cnames[-1] := lapply(DT1[,cnames[-1],with=FALSE], 
         function(x) gsub(" ", "_", x))] 
}) 
## user system elapsed 
## 10.90 0.11 11.06 

## Method 2 
system.time({ 
    for(cname in cnames[-1]) { 
     set(DT2, j=cname, value=gsub(" ", "_", DT2[[cname]])) 
    } 
}) 
## user system elapsed 
## 10.65 0.05 10.70 

## Method 3 
system.time({ 
    for(cname in cnames[-1]) { 
     DT3[ , cname := gsub(" ", "_", DT3[[cname]]), with=FALSE] 
    } 
}) 
## user system elapsed 
## 10.33 0.03 10.37 

Para más detalles sobre set() y :=, leer su página de ayuda, conseguido escribiendo ?set o ?":=".

+0

Este es un caso interesante. Aquí, 19 columnas de 20 están siendo reemplazadas; el RHS de ': =' es casi toda la tabla. La ventaja de ': =' es mayor cuando, por ejemplo, una o dos columnas se agregan a 20, o una o dos columnas de 20 se modifican. En esos casos, la mayoría de las columnas se dejan en su lugar y ': =' es mucho más rápido que copiar toda la tabla. –

+0

Además, 'set()' es una función nueva en v1.8.0 (aún no está en CRAN) que proporciona funcionalidad ': =' directamente. 'set()' puede ser mucho más rápido que ': =' cuando se asigna dentro de un bucle (para una programación más natural). Hay un ejemplo en las últimas NOTICIAS en la página de inicio. –

+1

@MatthewDowle - Gracias por sus comentarios.Me recordaron que, durante el fin de semana, había tenido una sensación persistente sobre la respuesta que había dado aquí, y me animaron a volver a visitar esto. Obviamente tenía buenas razones para sentirme molesto. Por favor, eche un vistazo a mi respuesta revisada. También ** agregue cualquiera de las sugerencias que tiene en sus comentarios al texto de mi respuesta **, donde cree que podrían ayudar. Echaré un vistazo a 'set()', pero aún no me siento calificado para discutirlo. Y, una vez más, ¡gracias por todo el trabajo que dedica al desarrollo continuo del paquete data.table! –

6

Usted puede hacer esto:

library("stringr") 
dt[, -1] <- lapply(dt[, -1], function(x) str_replace(x," ","_"))