2012-02-10 25 views
28

Ho un data.table con le colonne da 2 a 20 come stringhe con spazi (ad es. "Nome di specie"). Voglio eseguire str_replace() su tutte quelle colonne simultaneamente in modo che tutto il "Nome delle specie" diventi "Species_Name". Posso fare sia:Come si esegue applicare su un data.table?

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

o se lo tengo come un oggetto data.table, allora posso fare questo una colonna alla volta:

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

Come faccio a fare questo per tutte le colonne da 2 a la fine simile a quella di cui sopra?

risposta

30

Completamente riscritto sulla 2015/11/24, per correggere un errore nelle versioni precedenti.

Hai alcune opzioni.

  1. Processo tutte le colonne di destinazione con un call incorporata per lapply(), utilizzando := per assegnare i valori modificati in posizione. Questo si basa sul supporto molto pratico di := per l'assegnazione simultanea a diverse colonne denominate sul suo LHS.

  2. utilizzare un ciclo for di scorrere attraverso le colonne di destinazione una alla volta, utilizzando set() per modificare il valore di uno alla volta.

  3. utilizzare un ciclo for iterare su più "naive" chiamate a [.data.table(), ognuno dei quali modifica una singola colonna.

Questi metodi tutti sembrano circa altrettanto veloce, in modo che uno si usa essere in gran parte una questione di gusto. (1) è molto compatto e espressivo. È quello che uso più spesso, sebbene tu possa trovare (2) più facile da leggere. Poiché elaborano e modificano le colonne una alla volta, (2) o (3) avranno un vantaggio nella rara situazione in cui data.table è così grande che si corre il rischio di correre contro i limiti imposti dal proprio La memoria disponibile della sessione 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 

Per maggiori dettagli su set() e :=, leggere la loro pagina di aiuto, ottenuto digitando ?set o ?":=".

+0

Questo è un caso interessante. Qui, 19 colonne su 20 sono state sostituite; il RHS di ': =' è quasi tutto il tavolo. Il vantaggio di ': =' è maggiore quando, ad esempio, una o due colonne vengono aggiunte a 20 o una o due colonne di 20 vengono modificate. In questi casi la maggior parte delle colonne viene lasciata sul posto e ': =' è molto più veloce di copiare l'intera tabella. –

+0

Inoltre, 'set()' è una nuova funzione in v1.8.0 (non ancora in CRAN) che fornisce direttamente la funzione ': ='. 'set()' può essere molto più veloce di ': =' quando si assegna all'interno di un ciclo (per una programmazione più semplice e naturale). C'è un esempio nelle ultime notizie sulla home page. –

+1

@MatthewDowle - Grazie per i vostri commenti.Mi hanno ricordato che, durante il fine settimana, avevo avuto un sentimento fastidioso riguardo alla risposta che avevo dato qui e mi ha spronato a rivisitare questo. Ovviamente avevo buone ragioni per sentirmi tormentato. Si prega di dare un'occhiata alla mia risposta rivista. Inoltre ** per favore aggiungi i suggerimenti che hai inserito nei tuoi commenti al testo della mia risposta **, in cui ritieni che potrebbero aiutarti. Dare un'occhiata a 'set()', ma non mi sento ancora qualificato per discuterne. E, ancora una volta, grazie per tutto il lavoro che hai dedicato allo sviluppo continuo del pacchetto data.table! –

6

Si può fare questo:

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